Sortie turns issue tracker tickets into autonomous coding agent sessions — a single Go binary that orchestrates workspaces, retries, and state reconciliation for AI coding agents. The full picture is in the README.
The project follows a spec-first model: docs/architecture.md defines every entity, state machine, and validation rule. The implementation conforms to it. This matters because if you are fixing a bug in the orchestrator, the architecture doc tells you what the correct behavior is. You do not need to reverse-engineer intent from the code.
Browse open issues and look for the
labels good first issue and help wanted. These are curated for newcomers and do not
require deep familiarity with the codebase.
If nothing catches your eye, test coverage and documentation fixes are always useful and require no prior discussion:
# Find packages with low coverage
go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out | grep -v '100.0%' | sort -k3 -nFor larger work — new features, new adapters, architectural changes — open an issue first to discuss the approach.
Requirements: Go 1.26.1 (see go.mod), golangci-lint.
git clone https://github.com/sortie-ai/sortie.git
cd sortie
make test # runs all tests with -race
make build # compiles to ./sortie
make lint # golangci-lint
make fmt # gofmt + goimportsAll commands go through the Makefile. If make test passes, the change is safe to
submit.
The SQLite dependency is modernc.org/sqlite — a pure-Go driver. No C compiler needed.
Integration tests are gated by environment variables and skip cleanly without them:
SORTIE_JIRA_TEST=1 SORTIE_JIRA_ENDPOINT="..." SORTIE_JIRA_API_KEY="..." \
make test PKG=./internal/tracker/jira/...
SORTIE_GITHUB_TEST=1 SORTIE_GITHUB_TOKEN="ghp_..." SORTIE_GITHUB_PROJECT="owner/repo" \
make test PKG=./internal/scm/github/...
SORTIE_CLAUDE_TEST=1 ANTHROPIC_API_KEY="sk-..." \
make test PKG=./internal/agent/claude/...GitHub integration tests also accept an optional SORTIE_GITHUB_ISSUE_ID variable
(a valid issue number in the configured repo) to enable FetchIssueByID and
FetchIssueStatesByIDs test cases.
You do not need access to Jira, GitHub, or Claude to contribute. The unit test suite covers the vast majority of the codebase.
Small changes (docs, typos, test coverage, bug fixes in a single package): fork, fix, test, submit a PR. No ceremony needed.
Medium changes (multi-file bug fixes, new test scenarios, adapter improvements): read the relevant section of docs/architecture.md before implementing. The spec defines what correct behavior looks like, so reading it first prevents wasted effort.
Large changes (new features, new adapters, orchestrator changes): open an issue to discuss the design before writing code. The architecture doc is the source of truth — changes that contradict it will not be merged. If you believe the spec itself should change, that is a valid conversation to have in an issue.
cmd/sortie/ entry point, CLI wiring
internal/
agent/ agent adapters and shared agent helpers (agentcore/, claude/, codex/, copilot/, mock/, ...)
config/ typed config, defaults, env-var resolution
domain/ pure types, interfaces, error categories (imports nothing)
httpkit/ shared REST transport, conditional GET, pagination
issuekit/ shared issue normalization helpers
logging/ structured slog helpers (imports nothing)
maputil/ generic map utility helpers (imports nothing)
typeutil/ type coercion helpers (imports nothing)
orchestrator/ dispatch, retry, reconciliation, state machine
persistence/ SQLite store, migrations, retry queues
prompt/ text/template rendering, strict mode
registry/ adapter registration
server/ HTTP API, dashboard, metrics
tool/ agent tools (trackerapi/, history/, mcpserver/, status/)
tracker/ tracker adapters (jira/, file/, etc.)
scm/ SCM adapters (github/)
trackermetrics/ shared tracker-operation metrics helpers
workflow/ WORKFLOW.md parser, file watcher
workspace/ filesystem isolation, path safety, hook execution
docs/
architecture.md the specification (~3600 lines)
decisions/ Architecture Decision Records (ADRs)
Imports flow downward. domain/, logging/, maputil/, typeutil/, and httpkit/
sit at the bottom with no internal dependencies. issuekit/ and trackermetrics/
depend only on domain/. Adapters (tracker/*, scm/*, agent/*) implement
interfaces defined in domain/ and never import each other or the orchestrator.
The linter config in .golangci.yml catches most issues. Beyond what the linter enforces:
- Naming: core packages use generic names (
agent_*,tracker_*,session_*). Adapter-specific names (jira_*,claude_*) belong only inside their adapter package. - Errors: wrap with context (
fmt.Errorf("operation: %w", err)), no capitals, no trailing punctuation. Use the error categories ininternal/domain/errors.go. - Logging:
log/slogwith typedslog.Attrconstructors. Derive loggers vialogging.WithIssueandlogging.WithSession. - Templates:
Option("missingkey=error")on everytext/template— strict mode is mandatory.
- Table-driven tests with
t.Parallel()at both test and subtest level. t.Helper()as the first line of every test helper.t.TempDir()for filesystem isolation,t.Setenv()for environment variables.- Error assertions via
errors.As()/errors.Is(), never string matching. - Failure format:
FuncName(input) = got, want expected. - Standard library only — no third-party assertion frameworks.
- Fixtures live in
testdata/within each package.
Commit messages follow Conventional Commits:
feat(orchestrator): add stall detection for running sessions
fix(workspace): reject symlinks escaping workspace root
test(tracker): cover pagination edge cases in Jira adapter
PRs use the template. One logical change per PR.
CI runs make lint and make test — both must pass.
- CGo or any dependency requiring a C compiler.
- Adapter-specific logic in core packages (
internal/orchestrator/,internal/domain/). - Weakened workspace path containment or input sanitization — these are security boundaries.
- Behavior that contradicts docs/architecture.md.
If you are unsure whether a change fits, open an issue. A five-minute conversation saves hours of work.
Sortie is primarily developed with AI coding agents. Contributions using AI tools are
welcome under the same quality bar: the code must be correct, spec-conformant, tested,
and reviewed by you before submitting. make test and make lint must pass — not just
"the agent said it works."
Workspace path containment and input sanitization are security boundaries, not
convenience features. Changes to internal/workspace/ receive additional scrutiny. If
you find a vulnerability, report it privately rather than opening a public issue.
Contributions are licensed under Apache License 2.0.