diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..473bb5b9 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,36 @@ +# Code of Conduct + +## Our Pledge + +We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to a positive environment: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior: + +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate + +## Enforcement + +Project maintainers are responsible for clarifying standards of acceptable behavior and will take appropriate action in response to unacceptable behavior. + +Maintainers have the right to remove, edit, or reject comments, commits, code, issues, and other contributions that do not align with this Code of Conduct. + +## Reporting + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting the project maintainers directly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.0. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..423aca5e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,61 @@ +# Contributing to Gas Town + +Thanks for your interest in contributing! Gas Town is experimental software, and we welcome contributions that help explore these ideas. + +## Getting Started + +1. Fork the repository +2. Clone your fork +3. Install prerequisites (see README.md) +4. Build and test: `go build -o gt ./cmd/gt && go test ./...` + +## Development Workflow + +We use a direct-to-main workflow for trusted contributors. For external contributors: + +1. Create a feature branch from `main` +2. Make your changes +3. Ensure tests pass: `go test ./...` +4. Submit a pull request + +## Code Style + +- Follow standard Go conventions (`gofmt`, `go vet`) +- Keep functions focused and small +- Add comments for non-obvious logic +- Include tests for new functionality + +## What to Contribute + +Good first contributions: +- Bug fixes with clear reproduction steps +- Documentation improvements +- Test coverage for untested code paths +- Small, focused features + +For larger changes, please open an issue first to discuss the approach. + +## Commit Messages + +- Use present tense ("Add feature" not "Added feature") +- Keep the first line under 72 characters +- Reference issues when applicable: `Fix timeout bug (gt-xxx)` + +## Testing + +Run the full test suite before submitting: + +```bash +go test ./... +``` + +For specific packages: + +```bash +go test ./internal/wisp/... +go test ./cmd/gt/... +``` + +## Questions? + +Open an issue for questions about contributing. We're happy to help! diff --git a/README.md b/README.md index ddcdce42..14b22f20 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,31 @@ Beads = Railroad Tracks (the persistent ledger) The goal is a "village" architecture - not rigid hierarchy, but distributed awareness where agents can help neighbors when something is stuck. Whether this actually works at scale is something we're still discovering. +## Prerequisites + +- **Go 1.23+** - For building from source +- **Git** - For rig management and beads sync +- **tmux** - Required for agent sessions (all workers run in tmux panes) +- **Claude Code CLI** - Required for agents (`claude` command must be available) + ## Install +**From source (recommended for now):** + ```bash go install github.com/steveyegge/gastown/cmd/gt@latest ``` +**Package managers (coming soon):** + +```bash +# Homebrew (macOS/Linux) +brew install gastown + +# npm (cross-platform) +npm install -g @anthropic/gastown +``` + ## Quick Start ```bash diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..99de4b83 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,38 @@ +# Security Policy + +## Reporting a Vulnerability + +If you discover a security vulnerability in Gas Town, please report it responsibly: + +1. **Do not** open a public issue for security vulnerabilities +2. Email the maintainers directly with details +3. Include steps to reproduce the vulnerability +4. Allow reasonable time for a fix before public disclosure + +## Scope + +Gas Town is experimental software focused on multi-agent coordination. Security considerations include: + +- **Agent isolation**: Workers run in separate tmux sessions but share filesystem access +- **Git operations**: Workers can push to configured remotes +- **Shell execution**: Agents execute shell commands as the running user +- **Beads data**: Work tracking data is stored in `.beads/` directories + +## Best Practices + +When using Gas Town: + +- Run in isolated environments for untrusted code +- Review agent output before pushing to production branches +- Use appropriate git remote permissions +- Monitor agent activity via `gt peek` and logs + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.1.x | :white_check_mark: | + +## Updates + +Security updates will be released as patch versions when applicable. diff --git a/internal/wisp/io.go b/internal/wisp/io.go index 59c3b6e3..b7ce9b9c 100644 --- a/internal/wisp/io.go +++ b/internal/wisp/io.go @@ -100,11 +100,7 @@ func ListHooks(root string) ([]string, error) { var agents []string for _, e := range entries { - name := e.Name() - if len(name) > len(HookPrefix)+len(HookSuffix) && - name[:len(HookPrefix)] == HookPrefix && - name[len(name)-len(HookSuffix):] == HookSuffix { - agent := name[len(HookPrefix) : len(name)-len(HookSuffix)] + if agent := AgentFromHookFilename(e.Name()); agent != "" { agents = append(agents, agent) } } diff --git a/internal/wisp/types.go b/internal/wisp/types.go index 5ba06229..1a829a96 100644 --- a/internal/wisp/types.go +++ b/internal/wisp/types.go @@ -10,6 +10,7 @@ package wisp import ( + "strings" "time" ) @@ -72,6 +73,25 @@ func NewSlungWork(beadID, createdBy string) *SlungWork { } // HookFilename returns the filename for an agent's hook file. +// Agent identities may contain slashes (e.g., "gastown/crew/max"), +// which are replaced with underscores to create valid filenames. func HookFilename(agent string) string { - return HookPrefix + agent + HookSuffix + safe := strings.ReplaceAll(agent, "/", "_") + return HookPrefix + safe + HookSuffix +} + +// AgentFromHookFilename extracts the agent identity from a hook filename. +// Reverses the slash-to-underscore transformation done by HookFilename. +func AgentFromHookFilename(filename string) string { + if len(filename) <= len(HookPrefix)+len(HookSuffix) { + return "" + } + if filename[:len(HookPrefix)] != HookPrefix { + return "" + } + if filename[len(filename)-len(HookSuffix):] != HookSuffix { + return "" + } + safe := filename[len(HookPrefix) : len(filename)-len(HookSuffix)] + return strings.ReplaceAll(safe, "_", "/") }