@markjaquith/agency
v2.11.0
Published
Manage agentic work across repositories with durable workbases
Maintainers
Readme
@markjaquith/agency
Agency manages durable agentic work across repositories. Epics, tasks, and phases live as Markdown documents in a filesystem-backed workbase. Repository aliases and Git worktrees provide each execution unit with the code it may read or write.
Requirements
- Bun 1.0 or newer
- Git
- GitHub CLI for
agency pr create - OpenCode or Claude Code for
agency work - fzf for interactive work target selection
Installation
bun install -g @markjaquith/agencyFor development, run bun link from this repository.
Core Model
- A workbase is the root containing durable documents and local repository state.
- An epic orchestrates tasks, may inspect repositories, and never writes code.
- A task describes one durable outcome and may stand alone or belong to an epic.
- A phase belongs to a multi-phase task and represents one PR or intended PR.
- An execution unit is either a single-phase task or a phase. It has exactly
one writable
repo, optional read-onlyrepos, a branch, a base, and astring | nullPR URL.
Entity IDs come from directory names. Structured metadata lives in YAML 1.2 frontmatter; prose below it supplies human and agent context.
Workbase Layout
workbase/
AGENTS.md # managed workbase instructions
.opencode/
opencode.jsonc # managed task and epic references
agency.json
repos/
frontend/ # bare Git repository or symlink
backend/
epics/
checkout/
EPIC.md
tasks/
refresh-copy/ # single-phase task
TASK.md
code/ # created by agency work
frontend/
build-checkout/ # multi-phase task
TASK.md
phases/
backend-api/
PHASE.md
code/
backend/
frontend-ui/
PHASE.md
code/
frontend/
backend/Agency keeps discovery and other observational commands read-only. Run
agency integration status to inspect AGENTS.md and
.opencode/opencode.jsonc, then agency integration sync to create missing
files or refresh checksum-safe managed files. The OpenCode config grants
external-directory access to task and epic references. Customized files are
reported but never overwritten.
Repository metadata comes directly from Git under repos/{alias}. Workbase
configuration may provide a custom writable-worktree creation command.
Custom Worktree Command
By default, Agency creates worktrees with Git. Set worktreeCreateCommand to an
argv template when another tool should create writable worktrees:
{
"version": 2,
"worktreeCreateCommand": [
"my-worktree-tool",
"--repo",
"{repo}",
"--destination",
"{worktree}",
"--branch",
"{branch}"
]
}Available placeholders are:
{repo}: absolute repository alias path underrepos/{worktree}: absolute checkout path Agency requires{branch}: execution branch the custom command must create or check out{base}: configured execution base
{repo} and {worktree} are required. Agency invokes the command directly
without a shell, sets matching AGENCY_REPO, AGENCY_WORKTREE,
AGENCY_BRANCH, and AGENCY_BASE environment variables, and verifies that the
requested destination exists afterward.
Worktrunk can be configured per workbase without changing the user's Worktrunk path settings:
{
"version": 2,
"worktreeCreateCommand": [
"wt",
"-C",
"{repo}",
"-y",
"--config-set",
"worktree-path=\"{worktree}\"",
"switch",
"--create",
"--base",
"{base}",
"{branch}",
"--no-cd",
"--format",
"json"
]
}Custom commands own writable branch creation. Agency checks for conflicting
worktrees first, invokes the command only when the branch is not checked out,
and verifies that {worktree} exists afterward.
The configured command applies only to the writable checkout. Supplemental read-only repositories remain detached Git worktrees at their declared refs so they do not acquire writable branches.
Frontmatter
Epic
---
ticketUrl: https://example.com/tickets/checkout
description: Coordinate the checkout experience across frontend and backend.
repos:
- repo: frontend
ref: main
- repo: backend
ref: main
tasks:
- id: backend-api
- id: frontend-ui
dependsOn:
- backend-api
---Single-Phase Task
---
ticketUrl: https://example.com/tickets/refresh-copy
description: Refresh user-facing checkout copy.
epic: checkout
repo: frontend
repos:
- repo: backend
ref: main
branch: task/refresh-copy
base: main
pr: null
status: open
---Multi-Phase Task
---
ticketUrl: https://example.com/tickets/build-checkout
description: Deliver checkout through sequenced backend and frontend changes.
epic: checkout
phases:
- id: backend-api
- id: frontend-ui
dependsOn:
- backend-api
---Each listed phase has a phases/{id}/PHASE.md containing its execution fields:
---
description: Build the checkout interface against the new backend API.
repo: frontend
repos:
- repo: backend
ref: main
branch: task/checkout-ui
base: task/checkout-api
pr: null
status: open
---Epic task dependencies belong in EPIC.md. Phase dependencies belong in the
owning TASK.md. Stable IDs do not encode ordering in directory names.
Quick Start
agency init ~/work
cd ~/work
agency repo add frontend [email protected]:example/frontend.git
agency repo link backend ~/Dev/backend
agency task new
agency validate
agency context tasks/refresh-copy --json
agency work tasks/refresh-copy
agency pr create refresh-copyCommands
Target Context
agency context [target] --json returns the complete bootstrap context for an
epic, task, or phase without modifying the workbase or fetching repositories.
The target defaults to the current directory; entity directories, document
paths, checkout descendants, and bare task IDs are accepted.
The result includes workbase and target identity, ancestor frontmatter and prose
with SHA-256 hashes, dependency and readiness state, aggregate status, writable
and reference authority, local checkout and resolved-commit state, recorded PR
state, and validation warnings. Only done satisfies a dependency; dropped is
terminal but remains a blocker.
Complete output is the default. Pass --compact explicitly to omit document
prose and low-level Git details while retaining identity, hashes, authority,
paths, graph state, materialization state, and validation warnings.
Workbase Graph
agency graph --json exports the complete workbase as graph contract version 1.
Nodes use stable IDs (epic:<id>, task:<id>, phase:<task>/<phase>,
repository:<alias>, and execution-unit:<kind>/<id>). Typed edges are owns,
depends_on, writes, and references.
Every work node includes status, readiness, blockers, reverse dependents, and
aggregate progress. Only done satisfies a dependency. The graph summary counts
the statuses of all execution units, independent of filters.
agency graph [--json | --jsonl] [--ready | --blocked]
[--status <status>...] [--repository <alias>...] [--kind <kind>...]
[--include <bodies|workspace|git|pr>...]Filters are applied after graph state is computed. Returned edges always have both endpoints in the filtered node set. Durable frontmatter and document hashes are always present; prose, absolute workspace paths, Git inspection, and live PR inspection are opt-in include layers.
--jsonl emits a versioned meta record, one record per node and edge, then an
end record with counts. Combining the metadata with the streamed node and edge
records reconstructs the same result as --json.
Workbase and Repositories
agency init [path] [--json]
agency workbase add <path> [--json]
agency workbase list [--json]
agency integration status [--json]
agency integration sync [--json]
agency repo add <alias> <remote> [--json]
agency repo link <alias> <path> [--json]
agency repo list [--json]Registered workbases are stored in
$XDG_CONFIG_HOME/agency/workbases.json (or ~/.config/agency/workbases.json).
repo add creates a bare clone. repo link creates a symlink to an existing Git
repository. Alias names are then used by all documents and commands.
Commands that print Agency-owned results accept --json, including initialization,
integration inspection/sync, repository mutations, entity creation/list/show,
status, validation, graph export, and PR creation.
Epics
agency epic create <id> --ticket-url <url> [--description <text>] [--json]
--repo <alias>:<ref> [--repo <alias>:<ref>...]
agency epic list [--json]
agency epic show <id> [--json]Creating a task with --epic <id> adds the task to the epic and writes the task
back-reference.
Tasks
Create a task interactively. Text prompts identify optional values, and known
choices use fzf. This command requires a TTY and fails with --no-input:
agency task new [id]Create a single-phase task:
agency task create <id> --repo <alias>
[--ticket-url <url>] [--description <text>] [--epic <id>]
[--reference <alias>:<ref>...] [--branch <name>] [--base <name>] [--json]The branch defaults to task/<id> and the base defaults to main.
task create is always noninteractive and requires --repo for a single-phase
task. Use it instead of task new in scripts and agent workflows.
Create a multi-phase task container:
agency task create <id> --multi-phase
[--ticket-url <url>] [--description <text>] [--epic <id>] [--json]Noninteractive Use
Agency never prompts when --no-input is set or stdin/stderr are not TTYs.
--json also disables prompts and selectors, even when a TTY is available.
Commands with explicit inputs continue normally. task new fails immediately;
work requires an explicit directory, task ID, or --epic and must run from a
workbase; validate requires an explicit path or must run from a workbase.
Inspect tasks:
agency task list [--json]
agency task show <id> [--json]
agency task status <id> <open|working|delegated|done|dropped> [--json]To add a phase to an existing single-phase task, name the phase that will own
the task's current execution fields with --first-phase:
agency phase create refresh-copy verification
--first-phase implementation
--repo frontend --branch task/refresh-copy-verification --base main
--depends-on implementationAgency converts TASK.md to the multi-phase shape, creates both phase documents,
and moves existing worktrees from the task's code/ directory into the first
phase. Dependencies remain explicit through --depends-on.
Phases
agency phase create <task-id> <phase-id>
--repo <alias> --branch <name> --base <name>
[--description <text>] [--reference <alias>:<ref>...]
[--depends-on <phase-id>...] [--first-phase <phase-id>] [--json]
agency phase list <task-id> [--json]
agency phase show <task-id> <phase-id> [--json]
agency phase status <task-id> <phase-id> <open|working|delegated|done|dropped> [--json]Single-phase tasks and phases store status in YAML. New execution units start
open, and agency work marks the selected execution unit working immediately
before launch. Use the status subcommands to mark work delegated, done,
dropped, or open it again. The interactive work selector displays status
markers before execution units.
Archive
agency archive epic <epic-id> [--json]
agency archive task <task-id> [--json]
agency archive phase <task-id> <phase-id> [--json]Archived work keeps its hierarchy under archive/. Epic archiving includes its
listed tasks. Task and phase archiving update the active parent document and
reject items that active siblings depend on. Agency removes registered worktrees
before moving files, refuses dirty worktrees, and preserves branches.
Work and Pull Requests
agency work [<directory> | --epic <epic-id>] [--opencode | --claude]
agency pr create <task-id> [phase-id] [--draft] [--json]agency work presents the full hierarchy in fzf. Pass a directory, including
. for the current directory, to infer its epic, task, or phase. Outside a
workbase, Agency first presents the registered workbases, then the selected
workbase's hierarchy. If fzf is not installed, Agency prints the available
choices and asks for an explicit directory.
Epic and multi-phase task targets launch orchestration agents beside their
documents. Single-phase tasks and phases fetch repositories, create or reuse
worktrees under code/, and launch an execution agent in the writable checkout
with absolute context paths. An explicit directory or --epic target bypasses
the hierarchy chooser.
Each writable (repo, branch) pair may belong to only one task or phase. Agency
validation reports duplicate ownership, and agency work checks Git's worktree
registry before creating or reusing a checkout. It reuses only an exact
path/branch match; if the branch is checked out elsewhere or the target path has
the wrong branch, the command fails with the conflicting path instead of forcing
another checkout.
Read-only references use <alias>:<ref> on the CLI and { repo, ref } in YAML.
Agency resolves the ref to a commit and creates a detached worktree. Existing
reference worktrees are reused only while their commit still matches the declared
ref; use a commit SHA as ref when reproducibility matters.
agency pr create requires a clean writable worktree. It pushes the branch,
runs gh pr create --fill, and writes the returned GitHub PR URL into pr in
the owning TASK.md or PHASE.md.
Status and Validation
agency status [--json]
agency validate [path] [--json]Validation checks JSON and YAML parsing, Effect Schema conformance, repository aliases, parent/child backlinks, phase directories, duplicate references, unknown dependencies, and dependency cycles. YAML duplicate keys, anchors, aliases, and custom tags are rejected. When path is omitted outside a workbase, Agency prompts for a registered workbase.
Machine Protocol
--json emits exactly one JSON value on stdout for success or failure. It takes
precedence over --silent; progress, warnings, and verbose diagnostics remain on
stderr. Version 1 success responses have this shape:
{ "version": 1, "ok": true, "result": { "root": "/work/agency" } }Failures exit nonzero and use the same versioned envelope:
{
"version": 1,
"ok": false,
"error": {
"code": "CLI_USAGE",
"message": "Unknown command 'unknown'.\n\nUsage: agency <command> [options]",
"fields": {
"detail": "Unknown command 'unknown'.",
"usage": "agency <command> [options]"
},
"retryable": false,
"remediation": "Correct the arguments using the usage value in error.fields."
}
}Every error contains a stable code, human-readable message, structured
fields, and retryable. remediation is included when Agency knows a specific
recovery action. Version 1 defines these codes:
| Code | Meaning |
| ------------------------- | -------------------------------------------------------- |
| CLI_USAGE | Invalid command, option, argument, or option combination |
| WORKBASE_NOT_FOUND | No workbase could be resolved |
| WORKBASE_CONFIG_INVALID | Invalid workbase configuration |
| WORKBASE_REGISTRY_ERROR | Invalid or inaccessible workbase registry |
| FILE_NOT_FOUND | A required path does not exist |
| FILESYSTEM_ERROR | A filesystem operation failed |
| FRONTMATTER_INVALID | A durable document has invalid frontmatter |
| VALIDATION_FAILED | Workbase validation reported issues |
| REPOSITORY_ERROR | Repository operation failed |
| EPIC_ERROR | Epic operation failed |
| TASK_ERROR | Task operation failed |
| PHASE_ERROR | Phase operation failed |
| ARCHIVE_ERROR | Archive operation failed |
| WORKTREE_ERROR | Worktree operation failed |
| PULL_REQUEST_ERROR | Pull request operation failed |
| GRAPH_ERROR | Workbase graph construction failed |
| PROCESS_ERROR | A child process failed and may be retried |
| PROTOCOL_OUTPUT_ERROR | A command violated the machine output contract |
| COMMAND_FAILED | An otherwise unclassified command failure |
The Effect schemas are exported from @markjaquith/agency and
@markjaquith/agency/protocol. The distributable JSON Schemas are exported as
@markjaquith/agency/schemas/agency-envelope-v1.json and
@markjaquith/agency/schemas/agency-graph-v1.json. Representative envelope
payloads are exported as @markjaquith/agency/fixtures/protocol/success.json and
@markjaquith/agency/fixtures/protocol/error.json.
Agent Skill
skills/agency/SKILL.md contains an agent-oriented operating guide for Agency.
Install or link that directory into your agent's skill location when you want
Agency workflows to be discovered automatically.
Development
bun install
bun link
bun run buildRun focused tests with bun test <test-file>. Run formatting with bun format.
License
MIT
