@snappedly-tools/shipyard 0.6.0 → 0.7.0-staging.36081473933

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +64 -165
  2. package/dist/MountConfig-BHnKnA4h.d.ts +145 -0
  3. package/dist/{chunk-WAXEMZUV.js → chunk-44I2BL6E.js} +225 -33
  4. package/dist/chunk-44I2BL6E.js.map +1 -0
  5. package/dist/{chunk-56TDSWFU.js → chunk-JI3HDDMS.js} +3 -3
  6. package/dist/{chunk-56TDSWFU.js.map → chunk-JI3HDDMS.js.map} +1 -1
  7. package/dist/{chunk-FDYOTN55.js → chunk-L6PX5QTU.js} +253 -878
  8. package/dist/chunk-L6PX5QTU.js.map +1 -0
  9. package/dist/index.d.ts +117 -97
  10. package/dist/index.js +322 -344
  11. package/dist/index.js.map +1 -1
  12. package/dist/main.js +235 -139
  13. package/dist/main.js.map +1 -1
  14. package/dist/sandboxes/docker.d.ts +1 -3
  15. package/dist/sandboxes/docker.js +2 -4
  16. package/dist/templates/parallel-planner/main.mts +67 -9
  17. package/dist/templates/parallel-planner/planner-branch.mts +151 -0
  18. package/dist/templates/parallel-planner-with-review/main.mts +70 -12
  19. package/dist/templates/parallel-planner-with-review/planner-branch.mts +151 -0
  20. package/dist/templates/sequential-reviewer/main.mts +52 -3
  21. package/dist/templates/simple-loop/main.mts +51 -2
  22. package/package.json +1 -17
  23. package/dist/MountConfig-bZoCs4Dd.d.ts +0 -26
  24. package/dist/SandboxProvider-XJQqEdSf.d.ts +0 -261
  25. package/dist/chunk-ACD46ZM4.js +0 -136
  26. package/dist/chunk-ACD46ZM4.js.map +0 -1
  27. package/dist/chunk-FDYOTN55.js.map +0 -1
  28. package/dist/chunk-KMGNFXKN.js +0 -38
  29. package/dist/chunk-KMGNFXKN.js.map +0 -1
  30. package/dist/chunk-SOJTAJTF.js +0 -78
  31. package/dist/chunk-SOJTAJTF.js.map +0 -1
  32. package/dist/chunk-WAXEMZUV.js.map +0 -1
  33. package/dist/sandboxes/no-sandbox.d.ts +0 -37
  34. package/dist/sandboxes/no-sandbox.js +0 -4
  35. package/dist/sandboxes/no-sandbox.js.map +0 -1
  36. package/dist/sandboxes/vercel.d.ts +0 -104
  37. package/dist/sandboxes/vercel.js +0 -166
  38. package/dist/sandboxes/vercel.js.map +0 -1
  39. package/dist/templates/blank/main.mts +0 -13
  40. package/dist/templates/blank/prompt.md +0 -12
  41. package/dist/templates/blank/template.json +0 -4
package/README.md CHANGED
@@ -8,201 +8,100 @@
8
8
 
9
9
  [![CI](https://github.com/snappedly/shipyard/actions/workflows/ci.yml/badge.svg)](https://github.com/snappedly/shipyard/actions/workflows/ci.yml)
10
10
 
11
- Give Shipyard a backlog and a policy. It plans dependencies, runs AI coding
12
- agents in isolated sandboxes, reviews their work, and returns reviewable
13
- commits—without babysitting.
11
+ Give Shipyard a task or a GitHub issue. It runs Codex or Claude Code in an
12
+ isolated sandbox, can plan and review larger jobs, and brings the result back as
13
+ a commit or pull request you can inspect.
14
14
 
15
15
  ## The Shipyard advantage
16
16
 
17
- Most agent setups launch a CLI and hope for the best. Shipyard is the control
18
- plane around the agent:
17
+ - **Isolated work.** Docker keeps the agent's files and Git work inside a
18
+ sandbox while it runs.
19
+ - **Built for real projects.** Shipyard can sort issue dependencies, work on
20
+ independent tasks in parallel, and review the combined result.
21
+ - **You stay in control.** Runs have limits and logs. Issue workflows return a
22
+ pull request for you to review and merge.
19
23
 
20
- - **Protected execution:** Run Codex or Claude Code in an isolated Docker-backed
21
- sandbox with explicit mounts, credentials, and network access.
22
- - **Real orchestration:** Plan dependencies, parallelize safe work, leave
23
- blocked work alone, review each branch, and merge completed work.
24
- - **Failure-aware by design:** Use finite budgets, no-progress detection,
25
- cancellation, logs, and recovery artifacts instead of runaway loops.
26
- - **Reviewable output:** Runs preserve branches, worktrees, logs, and evidence;
27
- completed work comes back as commits. You keep control of the repository and
28
- the final release.
24
+ ## Try it on one task
29
25
 
30
- ## Install and run
26
+ You need **Node.js 20.18.1+**, **Git**, **Docker running**, and **Codex or Claude Code**
27
+ with a subscription login or API key.
31
28
 
32
- Before running Shipyard, install the [Snappedly skills](https://github.com/snappedly/skills)
33
- and run `setup-snapedly-skills` in the target repository.
29
+ Run:
34
30
 
35
- Requirements: Node.js 20.18.1+, Git, Docker, and credentials for your chosen
36
- agent. Run these commands in the repository Shipyard should change:
31
+ ```sh
32
+ npx skills add snappedly/skills
33
+ ```
34
+
35
+ Ask your coding agent to run `setup-snappedly-skills` in that repository.
37
36
 
38
37
  ```sh
39
38
  npm install --save-dev @snappedly-tools/shipyard
40
39
  npx shipyard init
41
40
  ```
42
41
 
43
- `init` asks for the agent, authentication, sandbox, issue tracker, and workflow
44
- template, then creates `.shipyard/`. For the first run, choose Docker and
45
- `blank` or `sequential-reviewer`.
42
+ During `shipyard init`, choose your agent, **Docker**, the template you want, and install the optional
43
+ [repository runner](docs/content/docs/repository-runner.mdx). Follow
44
+ the authentication prompts.
46
45
 
47
- Add the requested credentials to `.shipyard/.env`, write a task in
48
- `.shipyard/prompt.md` when using the `blank` template, then run:
46
+ On a local Mac, the repository runner automatically wakes Shipyard when you label an issue.
47
+ It runs as long as its terminal stays open.
49
48
 
50
- ```sh
51
- npx shipyard run
52
- ```
49
+ See the [getting started guide](docs/content/docs/index.mdx) for authentication and
50
+ branch options.
51
+
52
+ Fill in any credentials required in `.shipyard/.env`.
53
+ `GH_TOKEN` in `.shipyard/.env` to a GH token with Contents, Issues, and Pull
54
+ Requests read/write access and Metadata read access.
55
+ Set `SHIPYARD_ROUTINE_MODEL` and `SHIPYARD_STRONG_MODEL` in `.shipyard/.env`
56
+ for the roles your template uses. `simple-loop` uses routine for triage and
57
+ implementation. `sequential-reviewer` also uses strong for issue reviews.
58
+ Parallel planner templates use routine for ticket work and strong for planning,
59
+ conflict resolution, and integration. The review-enabled planner also uses
60
+ strong for ticket and final specification reviews. See
61
+ [agent setup](docs/content/docs/agents.mdx).
53
62
 
54
- The first run builds the Docker image automatically. Reuse it when the
55
- Dockerfile has not changed:
63
+ Commit the setup and prompt so the sandbox can read them. Make sure the Git ignore file keeps
64
+ `.shipyard/.env` out of the commit.
56
65
 
57
66
  ```sh
58
- npx shipyard run --skip-build
67
+ npx shipyard run
59
68
  ```
60
69
 
61
- For Codex, `init` can sign in with a ChatGPT subscription or configure an OpenAI
62
- API key. Claude Code supports a subscription token or an Anthropic API key. See
63
- the [agent guide](docs/content/docs/agents.mdx) for authentication details.
64
-
65
- ## Pick the workflow you need
66
-
67
- | Template | Best for | Built-in flow |
68
- | ------------------------------ | --------------------- | --------------------------------------------- |
69
- | `blank` | One custom task | One agent run |
70
- | `simple-loop` | A small issue backlog | Implement issues sequentially → review PRs |
71
- | `sequential-reviewer` | Safer issue delivery | Implement → review → review PR |
72
- | `parallel-planner` | Independent issues | Plan → implement in parallel → review PRs |
73
- | `parallel-planner-with-review` | Maximum autonomy | Plan → implement and review in parallel → PRs |
74
-
75
- All templates are generated TypeScript. Adjust prompts, models, iteration
76
- limits, branch strategy, hooks, and checks in `.shipyard/main.ts` or
77
- `.shipyard/main.mts`.
78
-
79
- ## Keep a repository running
80
-
81
- On Apple Silicon macOS, the optional repository runner keeps a foreground
82
- Shipyard controller ready for GitHub Issues. Label an issue `shipyard`; the
83
- controller wakes, drains a finite batch of eligible work, coalesces duplicate
84
- wake-ups, and stops when it makes no progress. Restarting it recovers work
85
- labelled while the host was offline.
86
- GitHub-backed `shipyard init` provisions `shipyard`, `shipyard:blocked`,
87
- `shipyard:pending`, `shipyard:complete`, and `shipyard:outstanding-tasks` in the repository.
88
- It also provisions the `bug`, `enhancement`, and five triage state labels.
89
- For a connected repository, init reports an error if any label cannot be created.
90
-
91
- The bundled issue workflows install Snappedly skills and the candidate's
92
- dependencies in Docker. When Shipyard takes an activated ticket, it runs
93
- `/triage` first and checks the current GitHub labels. Implementation requires
94
- both `shipyard` and `ready-for-agent`, with no conflicting triage state. Other
95
- triage outcomes follow the normal blocked flow: Shipyard adds
96
- `shipyard:blocked`, removes `shipyard`, and records the reason on the ticket.
97
- A standalone ready issue then runs through `/implement`. Activating
98
- a planning spec or a linked executable child resolves the parent and only
99
- linked tickets labelled `shipyard` into one `/implement-spec` scope. The sequential
100
- templates deliver selected tickets on one branch; the parallel templates assign
101
- ready tickets to `/implement` workers, integrate dependency waves, resolve ticket
102
- merge conflicts on the spec branch, and review the integrated change. One
103
- non-draft PR per spec awaits human merge. Later selected tickets update that PR.
104
- Shipyard also recognizes a ticket added to an open verified spec PR's `Source
105
- issues:` line as belonging to that spec, even without a GitHub sub-issue or
106
- `## Parent` link. Conflicting links block the selected ticket for correction.
107
- Selected tickets receive `shipyard:pending` while Shipyard works on them.
108
- Successful handoff replaces it with `shipyard:complete` and removes `shipyard`.
109
- The parent spec and PR show `shipyard:blocked` if an unfinished child is blocked,
110
- `shipyard:outstanding-tasks` if children remain, or `shipyard:complete` when all
111
- linked tickets are complete. Spec labels report child state; they never prevent
112
- a reactivated child from running. The issues remain open under the target
113
- repository's closure policy.
114
- With no labelled tickets yet, Shipyard marks the parent outstanding and waits
115
- to create the PR until a ticket is selected.
116
- If an attempted issue cannot be completed, Shipyard comments with the reason,
117
- marks the attempted tickets `shipyard:blocked`, clears `shipyard:pending`, and
118
- removes `shipyard` from the scope. The parent spec and any existing PR show
119
- `shipyard:blocked` while an unfinished child remains blocked. It does not
120
- publish a new PR for failed work. Resolve the problem, remove
121
- `shipyard:blocked` from a ticket, then add `shipyard` to retry that ticket;
122
- the parent spec's status label needs no manual change. Missing or ambiguous
123
- relationships block the affected selected issue and record the reason. If GitHub cannot confirm whether a
124
- PR became ready, Shipyard leaves the issue active for reconciliation. The GitHub token
125
- needs Contents, Issues, and Pull requests read/write permission plus Metadata
126
- read permission. Keep the Mac and foreground controller running for wake-ups.
127
- If GitHub rejects a failure comment, Shipyard keeps a local pending report for
128
- replay. A fresh `shipyard` activation on an unblocked ticket supersedes that
129
- report. Spec and PR status label failures are logged without stopping ticket
130
- work; retained activation lets the next invocation recalculate their labels.
131
-
132
- Accept runner installation during `init`, or install it later:
70
+ Or for the automated runner:
133
71
 
134
72
  ```sh
135
- npx shipyard runner install
136
- git add .shipyard .github/workflows/shipyard-wake.yml
137
- git commit -m "Add Shipyard wake workflow"
138
- git push
139
73
  npx shipyard runner start
140
74
  ```
141
75
 
142
- Run `npx shipyard runner purge` to remove every dated run-log folder and
143
- root-level `.log` file under `.shipyard/logs/`. Shipyard automatically removes
144
- entries older than eight days before `shipyard run`, at runner startup, and
145
- daily while the runner stays active. Use a path outside `.shipyard/logs/` for
146
- logs that must be retained separately.
147
-
148
- See the [repository runner guide](docs/content/docs/repository-runner.mdx) for
149
- requirements, lifecycle commands, and the security model.
76
+ ## Turn GitHub issues into pull requests
150
77
 
151
- ## Build your own coordinator
152
-
153
- Shipyard is also a TypeScript library. Compose your own workflow with
154
- `run()`, `createSandbox()`, and `createWorktree()` while reusing its agent,
155
- sandbox, branch, prompt, logging, cancellation, and session primitives.
156
-
157
- ```ts
158
- import { CODEX_MODELS, codex, run } from "@snappedly-tools/shipyard";
159
- import { docker } from "@snappedly-tools/shipyard/sandboxes/docker";
160
-
161
- await run({
162
- agent: codex(CODEX_MODELS.routine),
163
- sandbox: docker(),
164
- promptFile: ".shipyard/prompt.md",
165
- });
166
- ```
167
-
168
- Docker is the default path. Vercel Sandbox is available for isolated cloud
169
- execution; `noSandbox()` is available only for trusted repositories and prompts.
170
-
171
- ## What gets created
172
-
173
- ```text
174
- .shipyard/
175
- ├── main.ts or main.mts # workflow configuration
176
- ├── prompt.md # task or issue instructions
177
- ├── Dockerfile # sandbox image definition
178
- ├── .env # untracked credentials
179
- ├── logs/ # run logs
180
- ├── worktrees/ # isolated branch worktrees
181
- └── patches/ # recovery artifacts
182
- ```
78
+ Then:
183
79
 
184
- ## Security and control
80
+ 1. Write an issue with a clear goal and add the `shipyard` and
81
+ `ready-for-agent` labels.
82
+ 2. Make sure the runner is running, or start `npx shipyard run`. Shipyard checks the issue, implements it in Docker,
83
+ reviews the work, and opens a pull request.
84
+ 3. Inspect the pull request and merge it when you are happy with the result.
185
85
 
186
- Docker keeps the agent's repository and Git storage inside the sandbox by
187
- default. It is not a magic security boundary: mounts, credentials, devices,
188
- network access, host hooks, and `noSandbox()` can expand what an agent can do.
189
- Use least-privilege credentials and review generated configuration before
190
- running untrusted code. Read the [security evaluation](docs/security-evaluation.md)
191
- and [SECURITY.md](SECURITY.md).
86
+ ## Choose a workflow
192
87
 
193
- Shipyard runs in your infrastructure. There is no required hosted control
194
- plane; you control the host, Docker, model access, logs, and release policy.
88
+ | Template | What it does |
89
+ | ------------------------------ | -------------------------------------------------- |
90
+ | `simple-loop` | Works through labeled issues one at a time. |
91
+ | `sequential-reviewer` | Implements and reviews issues before PR handoff. |
92
+ | `parallel-planner` | Plans and works on independent issues in parallel. |
93
+ | `parallel-planner-with-review` | Adds review to the parallel workflow. |
195
94
 
196
- ## Learn more
95
+ Shipyard also exports TypeScript APIs for custom workflows. Configure prompts,
96
+ branches, limits, and hooks in the generated `.shipyard/main.ts` or
97
+ `.shipyard/main.mts`. See [configuration](docs/content/docs/configuration.mdx)
98
+ and [agent setup](docs/content/docs/agents.mdx).
197
99
 
198
- - [Getting started](docs/content/docs/index.mdx)
199
- - [Configuration](docs/content/docs/configuration.mdx)
200
- - [Repository runner operations](docs/runbooks/repository-runner-macos-validation.md)
201
- - [Contributing](CONTRIBUTING.md)
100
+ ## Safety and license
202
101
 
203
- ## License
102
+ Shipyard runs on your machine or infrastructure. Sandbox access depends on the
103
+ mounts, credentials, and network settings you choose. Read the
104
+ [security guide](docs/security-evaluation.md) before using untrusted code.
204
105
 
205
- Shipyard is source-available under the
206
- [PolyForm Strict License 1.0.0](LICENSE). It is available for permitted
207
- noncommercial use; the license does not permit redistribution, modification, or
208
- derivative works. Contact Snappedly to request a commercial license.
106
+ Shipyard is source-available under the [PolyForm Strict License 1.0.0](LICENSE)
107
+ for permitted noncommercial use. Contact Snappedly for a commercial license.
@@ -0,0 +1,145 @@
1
+ /** Result of executing a command inside a sandbox. */
2
+ interface ExecResult {
3
+ /** Collected standard output. */
4
+ readonly stdout: string;
5
+ /** Collected standard error. */
6
+ readonly stderr: string;
7
+ /** Process exit status. */
8
+ readonly exitCode: number;
9
+ }
10
+ /** Streams supplied when launching an interactive agent process. */
11
+ interface InteractiveExecOptions {
12
+ /** Input stream forwarded to the agent process. */
13
+ readonly stdin: NodeJS.ReadableStream;
14
+ /** Output stream receiving agent standard output. */
15
+ readonly stdout: NodeJS.WritableStream;
16
+ /** Output stream receiving agent standard error. */
17
+ readonly stderr: NodeJS.WritableStream;
18
+ /** Working directory inside Docker. */
19
+ readonly cwd?: string;
20
+ /** Abort signal that terminates the interactive process. */
21
+ readonly signal?: AbortSignal;
22
+ }
23
+ /** Handle to a running isolated sandbox. Docker implements this contract. */
24
+ interface IsolatedSandboxHandle {
25
+ /** Absolute Git workspace path inside Docker. */
26
+ readonly worktreePath: string;
27
+ /**
28
+ * Execute a command in Docker. Deliver `onLine` as output arrives so idle
29
+ * timeouts and live feedback work; buffered delivery does not satisfy this
30
+ * contract. Pipe `stdin` to the child rather than passing it as an argument.
31
+ */
32
+ exec(command: string, options?: {
33
+ /** Live output callback. */
34
+ onLine?: (line: string) => void;
35
+ /** Working directory inside Docker. */
36
+ cwd?: string;
37
+ /** Execute as root when supported. */
38
+ sudo?: boolean;
39
+ /** Input piped to the child process. */
40
+ stdin?: string;
41
+ /** Abort signal that terminates the command. */
42
+ signal?: AbortSignal;
43
+ /** Maximum combined output bytes before termination. */
44
+ maxOutputBytes?: number;
45
+ }): Promise<ExecResult>;
46
+ /** Launch an interactive process and terminate it when `signal` aborts. */
47
+ interactiveExec?(args: string[], options: InteractiveExecOptions): Promise<{
48
+ exitCode: number;
49
+ }>;
50
+ /** Copy a file or directory from the host into Docker. */
51
+ copyIn(hostPath: string, sandboxPath: string): Promise<void>;
52
+ /** Copy a file from Docker to the host. */
53
+ copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
54
+ /** Tear down the container. */
55
+ close(): Promise<void>;
56
+ }
57
+ /** File transfer shape used by agent session storage. */
58
+ interface SessionTransferHandle {
59
+ /** Absolute Git workspace path inside Docker. */
60
+ readonly worktreePath: string;
61
+ /** Run a command in the sandbox. */
62
+ exec: IsolatedSandboxHandle["exec"];
63
+ /** Launch an interactive command when available. */
64
+ interactiveExec?: IsolatedSandboxHandle["interactiveExec"];
65
+ /** Copy one host file into the sandbox. */
66
+ copyFileIn(hostPath: string, sandboxPath: string): Promise<void>;
67
+ /** Copy one sandbox file to the host. */
68
+ copyFileOut(sandboxPath: string, hostPath: string): Promise<void>;
69
+ /** Tear down the sandbox. */
70
+ close(): Promise<void>;
71
+ }
72
+ /** Inputs to Docker sandbox creation. */
73
+ interface IsolatedCreateOptions {
74
+ /** Original repository path used to derive the image name; never mounted. */
75
+ readonly hostRepoPath?: string;
76
+ /** Environment injected into the Docker container. */
77
+ readonly env: Record<string, string>;
78
+ }
79
+ /** Configuration for the isolated Docker provider contract. */
80
+ interface IsolatedSandboxProviderConfig {
81
+ /** Human-readable provider name. */
82
+ readonly name: string;
83
+ /** Provider environment merged into sandbox startup. */
84
+ readonly env?: Record<string, string>;
85
+ /** Start a sandbox and return its command and file-transfer handle. */
86
+ readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
87
+ }
88
+ /** Docker's isolated filesystem provider contract. */
89
+ interface IsolatedSandboxProvider {
90
+ /** Isolated filesystem discriminator. */
91
+ readonly tag: "isolated";
92
+ /** Human-readable provider name. */
93
+ readonly name: string;
94
+ /** Environment variables injected into Docker. */
95
+ readonly env: Record<string, string>;
96
+ /** Start a sandbox. */
97
+ readonly create: (options: IsolatedCreateOptions) => Promise<IsolatedSandboxHandle>;
98
+ }
99
+ /** Provider accepted by Shipyard's Docker execution path. */
100
+ type SandboxProvider = IsolatedSandboxProvider;
101
+ /** Create a temporary branch and merge its commits back to host HEAD. */
102
+ interface MergeToHeadBranchStrategy {
103
+ /** Branch strategy discriminator. */
104
+ readonly type: "merge-to-head";
105
+ }
106
+ /** Run on a caller-named branch. */
107
+ interface NamedBranchStrategy {
108
+ /** Branch strategy discriminator. */
109
+ readonly type: "branch";
110
+ /** Branch to create or reuse. */
111
+ readonly branch: string;
112
+ /** Starting ref for a new branch. */
113
+ readonly baseBranch?: string;
114
+ }
115
+ /** Supported Docker branch strategies. */
116
+ type BranchStrategy = MergeToHeadBranchStrategy | NamedBranchStrategy;
117
+ /** Construct the isolated provider contract used by Docker. */
118
+ declare const createIsolatedSandboxProvider: (config: IsolatedSandboxProviderConfig) => IsolatedSandboxProvider;
119
+
120
+ /**
121
+ * User-facing mount configuration for Docker.
122
+ *
123
+ * Each entry describes a host directory to mount into the sandbox container.
124
+ */
125
+ /** A single bind-mount descriptor for the Docker provider. */
126
+ interface MountConfig {
127
+ /**
128
+ * Path on the host. Supports:
129
+ * - Absolute paths (`/data/cache`)
130
+ * - Tilde-expanded paths (`~/data` → `<home>/data`)
131
+ * - Relative paths (`data` or `./data`) — resolved from `process.cwd()`
132
+ */
133
+ readonly hostPath: string;
134
+ /**
135
+ * Path inside the sandbox container. Supports:
136
+ * - Absolute paths (`/mnt/data`)
137
+ * - Tilde-expanded paths (`~/.npm` → `/home/agent/.npm`) — expanded using the provider's sandbox home directory
138
+ * - Relative paths (`data` or `./data`) — resolved from the worktree directory (`/home/agent/workspace`)
139
+ */
140
+ readonly sandboxPath: string;
141
+ /** Mount as read-only. Defaults to `false`. */
142
+ readonly readonly?: boolean;
143
+ }
144
+
145
+ export { type BranchStrategy as B, type ExecResult as E, type IsolatedSandboxProvider as I, type MountConfig as M, type NamedBranchStrategy as N, type SessionTransferHandle as S, type SandboxProvider as a, type MergeToHeadBranchStrategy as b, type InteractiveExecOptions as c, type IsolatedCreateOptions as d, type IsolatedSandboxHandle as e, type IsolatedSandboxProviderConfig as f, createIsolatedSandboxProvider as g };