@tablation/crew 0.0.0-stage → 0.1.1

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brad Choate
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,302 @@
1
- # Temporary Holding Version
1
+ # crew
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A standing team of headless agents that picks work off a
4
+ [Tablation](https://tablation.com) board, does it on a machine you control,
5
+ and reports back on the board.
6
+
7
+ **Documentation: <https://crew.tablation.dev>** — start with
8
+ [Getting started](https://crew.tablation.dev/getting-started). The source is in
9
+ `docs/`.
10
+
11
+ Each **seat** is a row in the board's Crew table that happens to be a robot,
12
+ with a brief (`prompts/<promptSet>/`, see "Prompt sets" below) and a slice
13
+ of the queue. A seat is named in that table and answers to that name, in the
14
+ queue digest and in the comments it writes on tickets. Everything the crew
15
+ knows about a run — what to build, what is blocked, what has shipped — is
16
+ table data, and every step it takes is visible as a status change or a
17
+ comment on the ticket. There is no hidden state and no queue but the board.
18
+
19
+ Every agent is handed a roster at the top of its prompt: who else is aboard,
20
+ what each of them is called, and which rows are **holds** — the people using
21
+ this ship, and the interactive sessions they work through. A ticket assigned
22
+ to a hold is off limits to every seat, whatever its status, which is how a
23
+ person takes something over without racing the crew for it.
24
+
25
+ Today's crew has four polled seats, described below under the `default`
26
+ prompt set (the three-lane dev/design/QA policy this repo ships with — see
27
+ "Prompt sets" below for others, and for writing your own):
28
+
29
+ | Seat | Owns | Brief |
30
+ | --- | --- | --- |
31
+ | **dev** | approved tickets that don't need design work | `prompts/default/personas/lane-dev.md` |
32
+ | **design** | approved tickets flagged *Needs design* | `prompts/default/personas/lane-design.md` |
33
+ | **qa** | everything at `fixed` or `qa`, whoever built it | `prompts/default/personas/lane-qa.md` |
34
+ | **triage** | tickets assigned to the triage seat | `prompts/default/personas/lane-triage.md` |
35
+
36
+ A fifth persona, **pair**, rides `crew agents sync` alongside these four but
37
+ is not polled: it is the identity a live, interactive session (an IDE
38
+ conversation, not a scheduled run) uses when it touches the tracker. It has
39
+ no Crew-table seat, is never assigned a ticket by the poll loop, and its
40
+ brief (`prompts/default/personas/lane-pair.md`) is not prefixed with
41
+ `common.md` — none of the polling loop's shared policy describes it. `crew
42
+ agents prompt pair` prints its current persona text (a workspace admin's
43
+ live edit if there is one, else the local default) for something like a
44
+ `SessionStart` hook to feed into a session at start.
45
+
46
+ Alongside personas, a prompt set can also ship **skills** —
47
+ `prompts/<promptSet>/skills/*.md`, each one YAML frontmatter (`name`,
48
+ `description`) plus a markdown prompt body. A skill isn't a seat: it's not
49
+ polled and not concatenated into every run's prompt, just synced into the
50
+ workspace's `Agent Skills` table so any session can fetch it by name on
51
+ demand. `crew agents sync [route]` pushes both personas and skills in one
52
+ run — "agents" here means every agent-shaped resource crew owns, not just
53
+ the Agents table; `crew skills sync [route]` is the same create/update/
54
+ diverged sync narrowed to skills alone, for when you've only touched
55
+ `skills/`. Example use — a Pair session invoked via an Epic's
56
+ `grill_link` looks up the `Grill-Me` skill through the Tablation MCP tool
57
+ `agent_skills_controller_get_skill` and follows it. `prompts/default/skills/
58
+ grill-me.md` is the shipped example.
59
+
60
+ One role runs per cycle, whichever holds the most urgent actionable ticket
61
+ (`src/priority.ts` decides, and the same module sorts the digest that agent is
62
+ handed, so the two can never disagree). QA outranks the building roles whenever
63
+ it has anything to check. If the winning role turns out to have nothing it can
64
+ actually do, the cycle falls through to the runner-up rather than idling.
65
+
66
+ Merging and deploying are **not** an agent's job. After the agent phase, a
67
+ release phase takes whatever the remote has, squash-merges every QA-verified
68
+ branch, bumps the version, writes the changelog and runs the repo's deploy
69
+ hook. A headless session is never handed permission to push to production.
70
+
71
+ A branch that will not merge is **handed back**, not skipped. The release
72
+ rewinds it, merges the base into the branch in its own worktree, and returns
73
+ the ticket to the dev lane with the conflict left in place to look at — so the
74
+ seat that resolves it is one with the ticket's context, and QA checks the
75
+ resolution like any other change. A branch that was merely stale merges
76
+ cleanly at that point and nobody is woken at all. Conflicting a second time
77
+ stops at `needs_info` rather than looping.
78
+
79
+ ## Prompt sets
80
+
81
+ The seats above and their briefs are policy, not mechanism — a fact about
82
+ *how* one particular workspace likes to work, not about what crew itself
83
+ can do. `prompts/` ships more than one of these as complete, ready-to-run
84
+ policies:
85
+
86
+ | Directory | Policy |
87
+ | --- | --- |
88
+ | `prompts/default/` | Three lanes — dev, design (gated by a *Needs design* flag), QA. |
89
+ | `prompts/dev-qa/` | Two lanes — dev builds everything, QA checks it. No design gate. |
90
+
91
+ A route picks one with `promptSet:` in `crew.yaml` (see
92
+ `crew.example.yaml`) — a bare name resolves under this repo's own
93
+ `prompts/`, defaulting to `default` when omitted. Different routes on the
94
+ same ship can run different prompt sets, since which workflow a workspace
95
+ wants is a fact about that workspace, not about the machine running it.
96
+
97
+ **Writing your own** is the expected path once a shipped preset doesn't
98
+ fit: copy a preset directory (`cp -r prompts/default ~/my-crew-policy`),
99
+ edit its prose, and point `promptSet` at the copy (`~/my-crew-policy` or a
100
+ relative path) — no fork of this repo required. A prompt set is a complete,
101
+ self-contained fork of `personas/common.md` + one `personas/lane-<role>.md`
102
+ per seat, plus whatever `skills/*.md` it wants, not a diff against another
103
+ one; each persona file is read as plain prose concatenated ahead of the
104
+ per-run roster/environment/queue sections
105
+ (`src/agent.ts`'s `assemblePrompt`), so there's no templating layer to
106
+ learn. `prompts/dev-qa/` is a worked example of trimming a lane out of
107
+ `default` cleanly, including the unused `lane-design.md` stub every
108
+ preset still needs today — see the next paragraph for why.
109
+
110
+ One current limit: **the role set itself is fixed** — `src/config.ts`'s
111
+ `RoleName` (`dev`, `design`, `qa`, `triage`, `pair`) — so even a prompt set
112
+ with no real use for a polled seat (`dev-qa`'s `design`) still needs a
113
+ `lane-<role>.md` file for every one of them, `pair` included, or `crew
114
+ agents sync` and `planAgentRun` throw looking for it. `prompts/dev-qa/
115
+ lane-design.md` handles this by being a brief that just says "do nothing,
116
+ you shouldn't be staffed" — copy that pattern for any polled seat your own
117
+ policy doesn't use (`pair` is never polled, so its own brief just needs to
118
+ exist, not disclaim itself). Making the seat set itself policy-defined, so
119
+ a prompt set could add or drop a role outright, is a larger change than
120
+ prompt sets took and hasn't been done.
121
+
122
+ ## What a workspace has to provide
123
+
124
+ The crew reads its meaning from the board, not from its own source. Statuses,
125
+ the priority order, and which column plays which role are **per-workspace
126
+ facts**, because a ship can be connected to several boards that each made
127
+ different choices. `docs/CONTRACT.md` documents the defaults and what a
128
+ workspace has to override if it names things differently.
129
+
130
+ ## Install
131
+
132
+ ```sh
133
+ git clone <this repo> crew
134
+ cd crew
135
+ cp crew.example.yaml ~/.config/crew/crew.yaml
136
+ chmod 600 ~/.config/crew/crew.yaml # it holds an API key
137
+ $EDITOR ~/.config/crew/crew.yaml
138
+ bin/crew doctor # read-only preflight
139
+ ```
140
+
141
+ The config lives in `~/.config/crew/` rather than in the checkout: it describes
142
+ the **machine**, so reinstalling or replacing the checkout does not lose it.
143
+ `crew` looks in `$CREW_CONFIG`, then `$XDG_CONFIG_HOME/crew`, then
144
+ `~/.config/crew/crew.yaml`, and only then beside the checkout.
145
+
146
+ `crew connect` resolves a workspace/project's ids into the state tree so you do
147
+ not have to look them up by hand. `doctor` then checks the config against
148
+ reality: the checkouts, the tools on PATH, the agent binary, the repo's hooks,
149
+ and whether the board answers. Nothing writes, wakes an agent or deploys until
150
+ a route has `enabled: true`.
151
+
152
+ Then install it as a real service:
153
+
154
+ ```sh
155
+ bin/crew install # writes and loads this platform's own units
156
+ bin/crew install --dry-run # see what it would do first
157
+ bin/crew uninstall # unload and remove them
158
+ ```
159
+
160
+ `install` writes three independent units — `run`, `release` and
161
+ `passengers` — and picks the mechanism itself per host: launchd on macOS, a
162
+ systemd **user** unit on Linux (falling back to a crontab line where
163
+ `systemctl` is not usable), or an error on Windows (not built yet). It always
164
+ uses an absolute interpreter path (`process.execPath`) and points each unit's
165
+ own log at a *different* file than the crew's own — pointing both at one file
166
+ was hit for real, and doubles every line.
167
+
168
+ `run` is a **persistent service**: `crew daemon`, the long-running loop that
169
+ chains cycles immediately when there's work and backs off when there isn't
170
+ (launchd `KeepAlive`/systemd `Restart=on-failure` restart it if it crashes).
171
+ Installing it starts it, the same as installing any other service would.
172
+ `bin/crew daemon start|stop|status|restart` control that same service
173
+ directly — useful without a full reinstall — except on the plain-crontab
174
+ fallback, which cannot supervise a persistent process and so keeps the old
175
+ one-shot-per-fire `crew run` instead. `release` and `passengers` stay on
176
+ their own fixed timers/crontab lines, one-shot per fire same as always: the
177
+ first run of each happens one interval after `install`, and each fire is a
178
+ few API calls — a full agent session only starts when that cheap check finds
179
+ something worth waking for.
180
+
181
+ The daemon also updates itself: on an idle pass (never mid-cycle) it checks
182
+ whether its own installed files (`src`/`dist`/`bin`, or the binary itself for
183
+ a compiled install) have changed since it started, and if so exits cleanly —
184
+ the same crash-recovery restart above then relaunches it against whatever is
185
+ now on disk. `crew daemon restart` forces this immediately, for a manual
186
+ `git pull && crew daemon restart` instead of waiting for the next idle tick.
187
+
188
+ `launchd/com.tablation.crew.plist` is kept only as a reference for what
189
+ `install` generates — hand-editing and loading it directly still works, but
190
+ `crew install`/`crew uninstall` is the supported path now.
191
+
192
+ ## Commands
193
+
194
+ ```
195
+ crew poll [route] decide a cycle and report it; writes nothing
196
+ crew run [route] [--role R] run the winning role's session, then release
197
+ crew daemon [route] run the persistent supervisor loop in the foreground
198
+ crew daemon start|stop|status control the installed `run` service directly
199
+ crew daemon restart stop then start it (force-picks-up an update)
200
+ crew release [route] merge what QA verified, version it, ship it
201
+ crew merge [route] merge verified branches and stop
202
+ crew deploy [route] release now, even with nothing new to merge
203
+ crew watch [route] live view of what the crew is doing
204
+ crew status [route] paused/running state
205
+ crew doctor [route] [--fix] preflight; --fix enables clean routes, offers crew install
206
+ crew ports [route] which checkout owns which ports, and what is up
207
+ crew reap [route] kill servers left behind by removed worktrees
208
+ crew drop [route] NNN remove a merged ticket's worktree and branch
209
+ crew sync [route] fast-forward the checkout and its worktrees from the remote
210
+ crew pause|resume [route] [R] pause everything, or one role
211
+ crew log [route] tail the log
212
+ crew inbox [--member NAME] your tickets across every workspace
213
+ crew connect WS[/PROJECT] resolve a workspace/project's ids into the state tree
214
+ crew repos add ROUTE PATH attach a local checkout to a route in crew.yaml (--dry-run previews)
215
+ crew repos list ROUTE the checkouts a route has, and the tracker Repos row each matches
216
+ crew install write and load this platform's scheduler unit
217
+ crew uninstall unload and remove it
218
+ ```
219
+
220
+ Every command that could change something takes `--dry-run`.
221
+
222
+ ## One ship, many boards
223
+
224
+ A ship connects to several workspaces at once, and ranks their queues against
225
+ each other — a P0 on one board outranks a P2 on another. The ship is identified
226
+ by `ship.name` matching a row in each board's Ships table; a crew member is
227
+ identified by email, so the same person is recognised across workspaces.
228
+
229
+ An area of development spans **several repositories**, so a checkout is a
230
+ property of the ticket, not of the route: `repos:` maps each name in the
231
+ board's Repos table to a directory on this machine. Naming even one repo
232
+ there makes it a closed list — several ships can divide a multi-repo area's
233
+ work between them, and anything not named is deliberately another ship's,
234
+ marked `NO CHECKOUT` in the digest rather than left blank (blank would read
235
+ as "work it here", which is the wrong directory).
236
+
237
+ Leaving `repos:` out entirely means the opposite: this ship serves
238
+ *everything* the board's Repos table lists, each checkout defaulting to
239
+ `<reposBasePath>/<workspace>/<repoName>` — `reposBasePath` is `~/Crew`
240
+ unless a `ship:` or route-level `reposBasePath:` says otherwise. A repo
241
+ that doesn't exist yet at its derived path is cloned there automatically
242
+ the first time a ticket actually needs it (from the Repos table's own
243
+ `remote` column, `owner/repo` over SSH) — not up front on `crew connect`,
244
+ which only discovers names and remotes, never fetches anything itself.
245
+
246
+ ## What lives where
247
+
248
+ ```
249
+ bin/crew the entry point
250
+ src/ the implementation (Node, run directly via type stripping)
251
+ test/ its tests, including a fake board for integration runs
252
+ prompts/ prompt sets — prompts/<name>/personas/{common.md,lane-<role>.md}
253
+ + prompts/<name>/skills/*.md
254
+ docs/ CONTRACT.md, REPO_SPEC.md, MIGRATION.md
255
+ launchd/ timer templates (edit the paths before installing)
256
+ crew.example.yaml copy to ~/.config/crew/crew.yaml
257
+ ```
258
+
259
+ The crew carries no ids, no absolute paths, no project commands and no device
260
+ names. Anything specific to a **machine** belongs in `crew.yaml`; anything
261
+ specific to a **repository** belongs in that repository's own `.crew.yaml`
262
+ (`docs/REPO_SPEC.md`), which declares its platform, hooks, branch naming,
263
+ versioning and release mode:
264
+
265
+ | hook | required | what it is for |
266
+ | --- | --- | --- |
267
+ | `test` | yes | run the suite before a release |
268
+ | `build` | yes | build it |
269
+ | `deploy` | when `release.mode: local` | ship it |
270
+ | `setup` | no | prepare a fresh worktree |
271
+ | `ports` | no | print this checkout's port assignments |
272
+ | `version` | no | print the current version |
273
+ | `bump` | no | produce and print the next one |
274
+ | `merged` | no | ask the forge whether a branch actually landed |
275
+ | `released` | no | confirm a commit is live (a sha, or an exact version) |
276
+
277
+ The crew carries no commands of its own: everything it runs to test, build,
278
+ version or ship a repository comes from that repository's own file.
279
+
280
+ One hook is the exception and lives in `crew.yaml` instead: `notify`, which is
281
+ handed a level (`ok` / `warn` / `fail`), a headline and a detail line whenever a
282
+ release ships or is blocked. Where that should be *shown* — a desktop
283
+ notification, a status widget, a webhook, a push — is a fact about the machine
284
+ and the person watching it, not about the code. Define none and release state
285
+ simply goes to the log.
286
+
287
+ A repo's own `.crew.yaml` wins over anything repeated in `crew.yaml`, and
288
+ `crew doctor` reports the duplication as drift. The client can still configure
289
+ a repo that has no `.crew.yaml` of its own.
290
+
291
+ ## Status
292
+
293
+ Live on macOS, driving this project's own board. Triage is a **seat**, not a
294
+ second process — there is one timer to install, not two.
295
+
296
+ The bash implementation this replaces has been deleted. Where its behaviour was
297
+ the only specification of something — the priority matrix, the QA digest, the
298
+ crew labels — it was captured as a fixture under `test/fixtures/` first, so the
299
+ tests still hold the port to what the original did.
300
+
301
+ Outstanding: Linux has not been exercised end to end, and the API key sits in
302
+ `crew.yaml` in plaintext until the device-code flow and keychain storage land.
package/bin/crew ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ // crew — the runner. See src/cli.ts.
3
+ //
4
+ // Runs the built output when it exists, and falls back to running TypeScript
5
+ // directly so a checkout works without a build step. The bash runner this
6
+ // replaces is kept as bin/crew-legacy.sh until cutover is done.
7
+ import { existsSync } from 'node:fs';
8
+ import { dirname, join } from 'node:path';
9
+ import { fileURLToPath, pathToFileURL } from 'node:url';
10
+
11
+ const here = dirname(fileURLToPath(import.meta.url));
12
+ const built = join(here, '..', 'dist', 'cli.js');
13
+ const source = join(here, '..', 'src', 'cli.ts');
14
+
15
+ // CREW_FROM_SOURCE=1 skips the bundle even when one exists. crew's own test
16
+ // suite sets it on every CLI it spawns (test/helpers/crew-bin.ts): dist/ is
17
+ // rebuilt by the release's build hook, which runs AFTER the test gate, so
18
+ // without this the gate exercises the previous release's bundle (CREW-988).
19
+ const fromSource = process.env.CREW_FROM_SOURCE === '1' && existsSync(source);
20
+
21
+ if (existsSync(built) && !fromSource) {
22
+ await import(pathToFileURL(built).href);
23
+ } else if (existsSync(source)) {
24
+ // Node >=22.18 strips types natively; older needs --experimental-strip-types.
25
+ await import(pathToFileURL(source).href);
26
+ } else {
27
+ console.error('crew: no dist/cli.js and no src/cli.ts — is this a complete checkout?');
28
+ process.exit(1);
29
+ }
@@ -0,0 +1,132 @@
1
+ # crew.yaml — what this ship is, and what it is connected to.
2
+ #
3
+ # Copy to ~/.config/crew/crew.yaml (NOT into the checkout): it describes this
4
+ # MACHINE, so replacing or reinstalling the crew checkout must not lose it.
5
+ # `crew` looks in $CREW_CONFIG, then $XDG_CONFIG_HOME/crew, then
6
+ # ~/.config/crew/crew.yaml, and only then beside the checkout.
7
+ #
8
+ # It holds an API key in plaintext, so: chmod 600.
9
+ #
10
+ # Unknown keys are an ERROR, not a warning. A typo that silently did nothing
11
+ # would be indistinguishable from a setting that does not work.
12
+
13
+ ship:
14
+ # Must match a row in the board's Ships table — that row is how the crew
15
+ # knows which seats are aboard here rather than on someone else's machine.
16
+ name: "My Mac"
17
+
18
+ # Detected from the host. Set it only to override.
19
+ # platform: macos | linux
20
+
21
+ agent:
22
+ bin: "/usr/local/bin/claude" # absolute: a timer runs with a minimal PATH
23
+ model: "claude-sonnet-5"
24
+ # Extended thinking budget, passed as MAX_THINKING_TOKENS. Defaults to
25
+ # 4096 when omitted — without it the CLI never emits `thinking` stream
26
+ # blocks, so Agent Log Cycles reporting has nothing to report. Set to 0
27
+ # to disable (less latency/cost, no cycles reported).
28
+ # maxThinkingTokens: 4096
29
+
30
+ # shell: bash # defaults per platform
31
+ extraPath: "/opt/homebrew/bin" # prepended for hooks
32
+ useNvm: true # source the repo's .nvmrc before hooks
33
+ # stateDir: "state" # defaults to "state", relative to THIS file
34
+ logFile: "/tmp/crew.log" # give each runner its own file — a shared one interleaves
35
+ # Defaults to "Mozilla/5.0 CrewAgent/<this checkout's version>". The
36
+ # Mozilla/5.0 prefix is load-bearing: Cloudflare blocks a bare tool
37
+ # User-Agent before it reaches the tracker API. Set this only to identify
38
+ # a specific ship in the tracker's own request logs.
39
+ # userAgent: "Mozilla/5.0 CrewAgent/1.0"
40
+
41
+ # Where a repo's checkout lives when a route's own `repos:` doesn't say so
42
+ # explicitly (see `repos:` below) — defaults to "~/Crew" if omitted here
43
+ # and at every route. A route-level `reposBasePath:` overrides this one.
44
+ # reposBasePath: "~/Crew"
45
+
46
+ # One ship, many boards. Each route is one workspace/project pair + one area
47
+ # of development within it — `crew run my-workspace/my-product`, the same
48
+ # string `crew connect` takes, addresses it; there is no separate `name:` to
49
+ # keep in sync with that. Keys are workspace-scoped in general, so a route
50
+ # normally carries its own — but if one key happens to be valid for all of
51
+ # them (a personal account key), declare it once as `ship.apiKey` instead and
52
+ # every route that omits its own picks it up.
53
+ routes:
54
+ - route: my-workspace/my-product
55
+ enabled: false # nothing writes, wakes an agent or deploys until this is true
56
+ area: "My Product" # the row of its Projects table this route works
57
+
58
+ # An area spans several repositories, and each needs its own checkout on
59
+ # this machine. Keyed by the name the board's Repos table uses. Naming
60
+ # even one repo here makes this a CLOSED list — a ticket for a repo not
61
+ # listed is one this ship deliberately doesn't work (another ship may),
62
+ # and the queue digest marks it NO CHECKOUT rather than leaving it blank.
63
+ repos:
64
+ My Product: "/home/me/src/my-product"
65
+ My Product CLI: "/home/me/src/my-product-cli"
66
+
67
+ # Leave `repos:` out entirely instead to serve every repo the board's
68
+ # Repos table lists, each one defaulting to
69
+ # `<reposBasePath>/my-workspace/<repoName>` and cloned there
70
+ # automatically (from that repo's own `remote` column) the first time a
71
+ # ticket actually needs it — nothing to list by hand, nothing fetched
72
+ # up front by `crew connect`.
73
+
74
+ # A single-repo route may use `dir:` instead of `repos:`.
75
+ # dir: "/home/me/src/my-product"
76
+
77
+ worktreePrefix: "myproject-issue-"
78
+
79
+ # Opt this route's ship into Host Passengers for this route's workspace
80
+ # (ISSUE-644): `crew connect` syncs this onto that workspace's own Ships
81
+ # row. Config-truth lives here, on the machine — never edit a Ships row
82
+ # by hand expecting it to stick. Defaults to false (not hosting).
83
+ # hostPassengers: true
84
+
85
+ # Which lane-behavior policy this workspace's agents follow — the
86
+ # prose in prompts/<name>/personas/{common.md,lane-<role>.md}, plus
87
+ # whatever prompts/<name>/skills/*.md it ships. Bare name ("dev-qa")
88
+ # picks a preset shipped under crew's own prompts/; a path
89
+ # ("./my-policy" or "~/my-crew-policy") points at a fully custom set
90
+ # you copied and edited yourself, so adopting your own workflow never
91
+ # requires forking crew. Defaults to "default" (the three-lane
92
+ # dev/design/QA policy this repo ships with) when omitted. See
93
+ # prompts/default/ for the shape a custom set needs to have.
94
+ # promptSet: "dev-qa"
95
+ # What a host must be to build a repo lives in THAT repo's own .crew.yaml
96
+ # (any | unix | macos | linux | windows) — never here. A route can span
97
+ # repos with different needs; the ship refuses a route only when it can
98
+ # satisfy none of them.
99
+ # Defaults to https://app.tablation.com when omitted here and on `ship:`.
100
+ # Only needed for a self-hosted tracker.
101
+ # baseUrl: "https://app.tablation.com"
102
+ apiKey: "REPLACE_ME" # or omit if `ship.apiKey` covers this workspace too
103
+
104
+ # Where release state should be SHOWN is a fact about this machine and the
105
+ # person watching it, not about the code — so unlike every other hook,
106
+ # notify lives here rather than in the repo's .crew.yaml. It receives
107
+ # CREW_LEVEL (ok|warn|fail), CREW_HEADLINE, CREW_DETAIL, CREW_ROUTE
108
+ # and CREW_SHIP, and decides everything else. Define none and release state
109
+ # simply goes to the log.
110
+ #
111
+ # hooks:
112
+ # notify: 'terminal-notifier -title "$CREW_HEADLINE" -message "$CREW_DETAIL"'
113
+
114
+ # Prefer putting hooks, labels and release settings in the REPO's own
115
+ # .crew.yaml (docs/REPO_SPEC.md) rather than here. A repo that carries one
116
+ # shadows anything repeated here, and `crew doctor` reports that as drift.
117
+ # These exist for a repo you cannot add a .crew.yaml to:
118
+ #
119
+ # hooks:
120
+ # test: "npm test"
121
+ # build: "npm run build"
122
+ # deploy: "./deploy.sh"
123
+
124
+ # Discovered from the board, not authored by hand, and NOT in this file:
125
+ # `crew connect my-workspace/my-product` (or a matching hand-filled JSON)
126
+ # writes state/resolved/my-workspace/my-product.json — workspaceId,
127
+ # projectId, areaModelId/areaId, the Issues/Comments/Crew model ids, each
128
+ # role's seat, the operator (the human this ship belongs to — set by
129
+ # hand; there is no way to derive it), and any hold (a row a person works
130
+ # through; a ticket assigned to one is off limits to every seat,
131
+ # whatever its status). Without it every cycle would re-resolve the same
132
+ # ids over the network instead of reading a local cache.