@mskyurina/agent-workspace
v0.3.0
Published
Transactional Git worktrees for isolated coding-agent changes and serialized integration.
Maintainers
Readme
agent-workspace
A small transaction layer for coding agents: one Git worktree per writer, durable task metadata, scope checks, and a single serialized integration path.
This repository is both:
- an Agent Skill under
skills/orchestrate-agent-workspaces/; - a zero-runtime-dependency Node.js CLI published as
@mskyurina/agent-workspace.
The CLI and core Skill are host-agnostic: any coding agent, script, or CI pipeline can invoke the transaction workflow. Files under agents/ provide optional host-specific metadata and are not required to run either layer.
It deliberately does not provide a daemon, distributed locks, containers, or semantic merge automation. The Skill plans the work; the CLI enforces the local Git isolation primitive.
Quick install
Install the Skill globally for your coding agent with the open-source Vercel Skills CLI:
npx skills add Hirate99/agent-workspace -gThe installer detects supported agents and lets you select the destinations. For non-interactive installation, add one or more -a <agent-id> options and -y.
Install the transaction CLI:
npm install --global @mskyurina/agent-workspaceThe two commands install different pieces: npx skills puts the instructions and bundled scripts where the selected agents can discover them, while npm install exposes the agent-workspace command on your PATH. The Skill can run its bundled CLI without a global CLI installation.
For a one-off CLI invocation without global installation:
npx --yes @mskyurina/agent-workspace --helpWe intentionally do not mutate agent directories from npm postinstall. Skill installation remains an explicit, reviewable operation, and npx skills also handles updates, removal, project/global scope, and other supported agents.
Requirements
- Git 2.31 or newer
- Node.js 18 or newer
- A repository with at least one commit
Bun is only required for contributing and running this repository's test suite.
Repository layout
skills/
orchestrate-agent-workspaces/
SKILL.md Agent instructions and trigger metadata
agents/ optional host-specific UI metadata
scripts/
agent-workspace.js generated, dependency-free CLI bundle
src/ TypeScript CLI source
bin/ npm executable launcher
tests/ unit, integration, real-world, and package testsThe standard skills/<name>/ layout lets npx skills add Hirate99/agent-workspace discover the Skill with the same one-line command while copying only the self-contained Skill directory, not the npm project or its development dependencies.
The TypeScript modules under src/ are the only hand-edited CLI implementation. npm run build deterministically bundles them into the single committed scripts/agent-workspace.js file so a remotely installed Skill can run immediately with Node.js and no build step. CI rebuilds the bundle and rejects any generated diff.
Workflow
# Verify the installed bundle and inspect compact state before creating another workspace.
agent-workspace version
agent-workspace status --summary --repo /path/to/coordinator
agent-workspace status --nonterminal --repo /path/to/coordinator
# With no branch request, start from the current branch and HEAD.
agent-workspace create T123 \
--repo /path/to/coordinator \
--expected-base 0123456789abcdef0123456789abcdef01234567 \
--scope src/payments \
--exclusive api-schema \
--verify \
--reuse
# If the user requested a new branch, create it from an explicit ref.
# Omit --base to use the repository default branch.
agent-workspace create T124 \
--repo /path/to/coordinator \
--new-branch feat/checkout \
--base develop \
--scope src/checkout \
--verify \
--reuse
# Additional concurrent writers can share that recorded target without
# switching the coordinator worktree or creating the user branch again.
agent-workspace create T125 \
--repo /path/to/coordinator \
--target feat/checkout \
--expected-base 0123456789abcdef0123456789abcdef01234567 \
--depends-on T124 \
--scope src/checkout \
--verify \
--reuse
# Append an audited path authorization without rebuilding an active worker.
# Read the current revision from `status T123` immediately before this command.
agent-workspace scope add T123 \
--repo /path/to/coordinator \
--scope src/payments/routes \
--expected-revision <sha256-from-status>
# Reproducibly install dependencies in the returned worktree.
agent-workspace prepare T123 --repo /path/to/coordinator
# Run tests or services with the task runtime namespace.
agent-workspace exec T123 --repo /path/to/coordinator -- npm test
# Work and commit inside the returned worktree, then submit it.
agent-workspace submit T123 --repo /path/to/worker
# Inspect task-ID dependency order instead of arranging commit SHAs.
agent-workspace plan T124 --repo /path/to/coordinator
# Integrate only into the recorded target at its exact expected HEAD.
# Checks are optional and repeatable. The internal worker is cleaned by default.
agent-workspace integrate T123 \
--repo /path/to/coordinator \
--target feat/refactor \
--expected-head 0123456789abcdef0123456789abcdef01234567 \
--check "npm run typecheck" \
--check "npm test"
# Preview old integrated workspaces, then explicitly clean that set.
agent-workspace prune --repo /path/to/coordinator
agent-workspace prune --repo /path/to/coordinator --apply <plan-token-from-preview>
# Recover a recorded directory left behind after Git already removed its worktree metadata.
agent-workspace cleanup T123 --repo /path/to/coordinator --force
# Diagnose stale records and interrupted operations without changing them.
agent-workspace doctor --repo /path/to/coordinatorState commands emit JSON. New task records preserve the base, target, dependencies, dirty-source
opt-in, and successful creation verification. --reuse returns the same active or submitted task
only from its recorded coordinator and only when its provided guards still match. --verify
checks write access, Git safety, and the conservative Windows path budget before activating a
first-time task; failure rolls back that creation instead of leaving a workspace behind. An
interrupted creating record is recovered before the same task ID is created again.
status <task> includes a deterministic SHA-256 revision. scope add is limited to active tasks
and the recorded coordinator, accepts only appended scopes, rejects stale revisions, validates the
complete live working tree against the expanded boundary, and preserves an audit trail of every
scope change. status --summary and status --nonterminal avoid loading terminal history into an
agent context and surface invalid legacy records without trusting them. doctor classifies
missing, orphaned, stale, wrong-branch, pending-cleanup, invalid, healthy, and terminal records
while printing recovery guidance without applying it. Mutating commands remain strict when durable
state is malformed.
An ordinary linked worktree can be the coordinator, so a writer can create an independent peer
without switching to the primary checkout. If the coordinator is dirty, creation fails unless
--allow-dirty-source explicitly accepts that the peer starts from committed HEAD and excludes
local changes. A CLI-managed worker cannot create nested workers.
prepare and exec attach to the child process and preserve its exit code. Run
agent-workspace --help for all options.
Cleanup writes pendingCleanup before removing Git or filesystem state and records each completed
phase. Retrying cleanup resumes the persisted operation and its explicit force authorization while
rechecking current worktree identity and orphan-directory safety.
Use one transaction per writing agent, not one per commit or sequential refactor phase. Reuse the returned worktree for that writer's full task. Additional workspaces are for genuinely concurrent, independent writers.
Lightweight runtime isolation
Each task receives a unique, durable runtime profile in addition to its worktree:
PORTandAGENT_WORKSPACE_PORTuse the task port. Creation skips ports that are already bound.TEMP,TMP, andTMPDIRpoint to an OS temporary path namespaced by repository and task, outside the repository tree.COMPOSE_PROJECT_NAMEkeeps normal Compose networks, volumes, and containers task-specific.AGENT_WORKSPACE_DB_NAMESPACEandAGENT_WORKSPACE_REDIS_PREFIXprovide safe names for application-level database and Redis isolation.AGENT_WORKSPACE_ID,AGENT_WORKSPACE_NAMESPACE,AGENT_WORKSPACE_WORKTREE, andAGENT_WORKSPACE_RUNTIME_DIRare available to scripts.
prepare selects a frozen install from packageManager or an unambiguous package-lock.json, pnpm-lock.yaml, yarn.lock, bun.lock, or bun.lockb. Override it for other ecosystems with prepare T123 -- <command>, or commit a small project configuration:
{
"prepare": ["npm", "ci"],
"env": {
"DATABASE_SCHEMA": "${dbNamespace}",
"REDIS_KEY_PREFIX": "${redisPrefix}",
"APP_URL": "http://127.0.0.1:${port}"
}
}Supported templates are ${id}, ${namespace}, ${port}, ${worktree}, ${runtimeDir}, ${tempDir}, ${dbNamespace}, ${redisPrefix}, and ${composeProject}. Reserved AGENT_WORKSPACE_*, PORT, COMPOSE_PROJECT_NAME, TEMP, TMP, and TMPDIR variables cannot be overridden.
This is namespace isolation, not virtualization. A port can still be claimed after its availability check, and an application with hard-coded ports, database names, Redis keys, Compose container_name, or shared build output must be configured to consume the profile. If it cannot be configured, declare the resource --exclusive and run those tasks serially. The CLI does not provision or destroy external databases or Redis instances.
Safety model
- Task records live in
<git-common-dir>/agent-workspace/tasksand are shared by linked worktrees. submitrequires the recorded worker branch to be clean and rejects undeclared paths, including both sides of renames, merge commits, and no-op tasks.createrecords the coordinator's current branch as its target unless--new-branchexplicitly creates a user branch from--baseor the repository default branch.--targetlets additional concurrent writers reuse an existing batch target without switching the coordinator.--expected-baseguards the resolved worker snapshot, while--reuseprevents repeated invocations with the same task ID from creating another worktree.--verifymakes first-time creation transactional: a durablecreatingrecord is written first, and access or path verification failure removes the worker, branches, and record.--depends-onpersists task DAG edges.planemits dependency order by task ID.- Exclusive resource names prevent known hotspots from being scheduled concurrently.
integraterequires the recorded coordinator worktree to be clean, attached to--target, exactly at--expected-head, and descended from every integrated dependency on that same target.- Repository mutations share the legacy-compatible state and integration locks, so creation cannot observe a transient integration HEAD. Locks whose recorded process has exited are recovered.
- Cherry-pick conflicts are aborted. Checks must leave the coordinator on the authorized branch at the exact candidate HEAD with a clean worktree. Failed checks restore the target without resetting an unrelated branch selected by a check.
- Integration progress is recorded before target mutation. A validated integration interrupted before its final state write is finalized on retry; an unvalidated attempt is restored and rerun when the target still matches the recorded transaction. Divergence requires manual recovery.
- Successful integration removes the internal worktree and
agent-workspace/*branch by default while preserving user branches. Use--keep-worktreeonly when needed. cleanuprecovers pending integration state before removing anything and refuses to discard non-integrated work or a worker that changed after submission unless--forceis explicit. If Git unregisters a worktree but Windows cannot delete a long residual path, the same cleanup attempt finishes the exact recorded directory with long-path support. A later retry prints a copyablecleanup ... --forcecommand and removes the orphan only when it has no.gitidentity, is not a link, and resolves outside every registered worktree.prunereturns a plan token and only removes the exact unchanged preview set when that token is passed to--apply.
This prevents physical workspace conflicts and catches declared scope violations. It cannot prove that independently edited code is semantically compatible; repository-wide tests and contract checks remain the integration gate.
Branch checkout, a clean worktree, transaction status, and command-lock absence are snapshots, not agent-liveness signals. They can show no evidence of an active writer, but they cannot prove that an agent or process has exited.
Releasing
Prepare a stable version in the pull request:
npm run release:prepare -- patchUse minor, major, or an explicit x.y.z version when appropriate. Commit the resulting package.json change with the rest of the pull request.
After the pull request merges, the publish workflow examines the version on main. If that version already has a tag, the merge is not a release and the workflow exits successfully. For a new version it runs the complete release gates, creates an annotated tag named exactly x.y.z, publishes the npm package through trusted publishing, and creates a GitHub Release with generated notes.
The workflow is restartable. If a failed run already created the tag at the merge commit, rerunning the same workflow continues with any missing npm publish or GitHub Release steps. To resume an older version explicitly:
gh workflow run publish.yml --ref main -f version=0.1.3Development
git clone https://github.com/Hirate99/agent-workspace.git
cd agent-workspace
bun install --frozen-lockfile
npm run build
bun run typecheck
bun test
bun run test:coverage
bun run test:packageThe end-to-end tests create disposable Git repositories and exercise real worktrees, concurrent TCP services, npm preparation without Bun, per-task temporary directories and namespaces, occupied ports, child exit codes, concurrent submission, serialized integration, commit conflicts, scope enforcement, rollback, and cleanup behavior. The package smoke test builds the actual npm tarball, checks its bundled Skill contents, installs it into a clean consumer project, and invokes the installed CLI with Node.js and no Bun. Coverage fails below 80% for lines, functions, or statements. GitHub Actions runs the same gates on Windows and Ubuntu.
