agent-workspace

module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: MIT

README

Agent Workspace (aw)

CI

A workspace-local command and package runtime for coding agents.

aw discovers the current repository, exposes existing package scripts, lets an agent persist useful commands, and installs namespaced command packages into the repository. It is a normal CLI, so Codex, Claude Code, Hermes, OpenCode, and humans use the same interface.

Status

v0.4.1 is a working local-first MVP:

  • finds a workspace from nested directories;
  • detects Git, GitHub Actions, pnpm/npm/yarn, Python, Go, Cargo, Taskfile, just, Cloudflare, Vercel, and Netlify markers;
  • imports package.json scripts using the detected package manager;
  • stores agent-authored commands in .agent/workspace.yaml;
  • runs commands at the workspace root with argument forwarding and exit-code propagation;
  • stamps snapshot: git commands and returns exit code 4 when the workspace changed during execution;
  • installs local directories or a package subdirectory from a fixed Git ref under .agent/packages/<name>;
  • records the resolved Git commit plus a SHA-256 package digest;
  • namespaces package commands as <package>:<command>;
  • rejects modified installed packages;
  • ships fixture-tested GitHub CI and PR-review watcher packages;
  • persists command-pattern triggers in workspace or package manifests;
  • routes trigger results through wake or a session-isolated deferred inbox.

Hosted registries, webhooks, automatic shell interception, and remote notification adapters are intentionally not in the core CLI.

Install

go install github.com/bkmashiro/agent-workspace/cmd/aw@latest

From a local checkout:

go install ./cmd/aw
# or
go build -o bin/aw ./cmd/aw

Quick start

cd your-project
aw init
aw inspect
aw list

aw add verify --description "Run repository verification" -- \
  pnpm lint '&&' pnpm typecheck '&&' pnpm test

aw run verify

A project that already has package.json scripts does not need aw init before discovery:

aw list
# pnpm:build   package.json script [package.json]
# pnpm:test    package.json script [package.json]

aw run pnpm:test

Pass extra arguments after --:

aw run pnpm:test -- --runInBand

Workspace manifest

version: 1
commands:
  verify:
    run: go test ./... && go vet ./...
    description: Run repository verification
  full-test:
    run: pnpm test
    description: Run the full test suite
    snapshot: git
triggers:
  ci-after-push:
    match: git push*
    run: github:ci
    delivery: defer

snapshot: git hashes the starting Git state, including tracked diffs and untracked files. If the state changes before the command exits, aw reports the result as stale and exits 4 rather than treating an old green result as current verification.

It is a validity stamp, not an isolated worktree: v0.4 does not prevent concurrent writes while the command runs.

Packages

A package is a directory containing package.yaml and optional scripts/assets:

name: repo-tools
version: 0.1.0
commands:
  summary:
    run: "$AW_PACKAGE_DIR/scripts/summary.sh"
    description: Print a compact repository summary

Install it into the current workspace:

aw install ./examples/packages/repo-tools
aw run repo-tools:summary

Package commands receive:

AW_WORKSPACE_ROOT  absolute workspace root
AW_PACKAGE_DIR     installed package directory
AW_COMMAND         resolved command name

Packages are copied into .agent/packages/, symlinks are rejected, and every list or run verifies the installed content against .agent/workspace.lock.

Install from a Git repository and pin the resolved commit in the lockfile:

aw install https://github.com/bkmashiro/agent-workspace.git \\
  --ref main \\
  --subdir examples/packages/github

--ref accepts a commit, tag, or branch fetch ref, but the lockfile always records the resolved commit SHA and content digest. Hosted package discovery and version resolution remain out of scope.

GitHub watcher package

The included github package requires an authenticated gh CLI:

aw install ./examples/packages/github

# Watch all workflow runs for the current HEAD.
aw run github:ci

# Wait for a review decision or new review/comment on the current PR.
aw run github:pr-review

Both commands accept bounded polling options:

aw run github:ci -- --timeout 1800 --poll 10
aw run github:pr-review -- --timeout 86400 --poll 30

github:ci waits for runs to appear, coalesces workflow state, and emits at most the last 160 lines of failed logs. It exits 0 when all runs succeed, 1 on a terminal failure, and 2 on timeout/configuration errors.

github:pr-review returns recent bounded review/comment bodies. It exits 1 for CHANGES_REQUESTED, 0 for approval or other new activity, and 2 on timeout/configuration errors.

The package also contributes github:after-push, a deferred git push* trigger that runs github:ci. Installing a package makes its triggers discoverable but does not install a global shell hook.

Triggers and deferred inbox

A trigger maps an observed shell command to an aw command:

aw trigger add ci-after-push \\
  --match 'git push*' \\
  --run github:ci \\
  --delivery defer

aw trigger list --json
aw trigger match --json -- git push origin main

aw does not intercept arbitrary shell processes. A harness hook, wrapper, or agent fires the trigger only after the observed command succeeds:

aw trigger fire --session "$SESSION_KEY" --delivery defer -- git push origin main

fire executes every matching trigger command. Delivery controls what happens afterward:

  • wake: stream the command result and propagate its exit code. A harness can use its normal completion notification to resume the agent.
  • defer: store the bounded result in the session inbox and return 0, even when the watched command failed. This avoids an immediate LLM call.

Pass --delivery defer from adapters that cannot surface synchronous wake output; the filter prevents wake triggers from running and being silently discarded. Omit it for manual use when both policies should fire.

For a long-running deferred watcher, launch aw trigger fire with the host's tracked background primitive and disable completion notification. A simple consumer can drain on the next existing turn:

aw inbox list --session "$SESSION_KEY" --json
aw inbox drain --session "$SESSION_KEY" --json

Adapters that inject results into an LLM turn should use the loss-safe two-phase protocol across every workspace touched by that session:

# pre_llm_call: atomically move pending events to a retryable lease.
aw inbox claim --all --session "$SESSION_KEY" --json

# post_llm_call, only after a successful turn: consume those leases.
aw inbox ack --all --session "$SESSION_KEY" --json

A failed API call leaves the lease intact, so the next claim returns the same events. Events arriving during the current turn remain pending and are not removed by ack. drain is the convenience claim + ack operation for consumers that do not need retry semantics.

Runtime state lives outside the repository under $AW_STATE_HOME, $XDG_STATE_HOME/aw, or ~/.local/state/aw; the workspace only stores trigger definitions. AW_SESSION_ID or HERMES_SESSION_ID can provide the default key, otherwise pass --session explicitly.

The CLI provides the deterministic substrate. Automatic hook invocation and context injection belong in small, explicitly enabled harness adapters.

Background use

Commands remain foreground processes. The host harness owns lifecycle:

terminal(
  command="aw run full-test",
  background=true,
  notify_on_complete=true
)

Use completion notification for wake; omit it for defer and drain the inbox during the next already-occurring turn.

Agent discovery

A repository only needs a compact instruction:

Run `aw list --json` to discover workspace commands before guessing workflows.

The full package documentation does not need to occupy the model context.

Development

go test ./...
go test -race ./...
go vet ./...
go build ./cmd/aw

License

MIT

Directories

Path Synopsis
cmd
aw command
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL