@titan-design/active-work 0.1.0 → 0.3.0
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/README.md +15 -6
- package/dist/aw.js +136 -35
- package/dist/aw.js.map +1 -1
- package/dist/chunk-HSGZOWS3.js +2605 -0
- package/dist/chunk-HSGZOWS3.js.map +1 -0
- package/dist/cli.js +6083 -2052
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/index.html +13 -5
- package/docs/cli-reference.md +1090 -0
- package/package.json +28 -5
- package/scripts/gen-cli-reference.mjs +23 -2
- package/skill/SKILL.md +46 -10
- package/skill/references/auditing-existing-work.md +14 -10
- package/skill/references/cli-dev.md +3 -2
- package/skill/references/onboarding.md +5 -9
- package/dist/chunk-OET6AFME.js +0 -1276
- package/dist/chunk-OET6AFME.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@titan-design/active-work",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Durable workspace state for engineering work — CLI, MCP, and Claude skill for tracking initiatives across sessions",
|
|
6
6
|
"license": "MIT",
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"skill",
|
|
23
23
|
"claude-commands",
|
|
24
|
-
"scripts"
|
|
24
|
+
"scripts",
|
|
25
|
+
"docs/cli-reference.md"
|
|
25
26
|
],
|
|
26
27
|
"engines": {
|
|
27
28
|
"node": ">=22"
|
|
@@ -33,6 +34,16 @@
|
|
|
33
34
|
"build:cli": "tsup",
|
|
34
35
|
"build:dashboard": "vite build --config src/dashboard/vite.config.ts",
|
|
35
36
|
"gen:cli-reference": "pnpm build:cli && node scripts/gen-cli-reference.mjs",
|
|
37
|
+
"mine:session": "node tools/mine-session-signals.mjs",
|
|
38
|
+
"index:session": "node tools/build-session-index.mjs",
|
|
39
|
+
"mine:files": "node tools/mine-file-history.mjs",
|
|
40
|
+
"mine:drain": "node tools/mine-drain.mjs",
|
|
41
|
+
"mine:drain-eval": "node tools/eval-drain.mjs",
|
|
42
|
+
"export:aw-data": "node tools/export-aw-data.mjs",
|
|
43
|
+
"cost:rollup": "node tools/cost-rollup.mjs",
|
|
44
|
+
"eval:miner": "node tools/eval-miner.mjs",
|
|
45
|
+
"index:eval": "node tools/eval-session-index.mjs",
|
|
46
|
+
"check:tools": "for f in tools/*.mjs; do node --check \"$f\" || exit 1; done && node -e \"JSON.parse(require('fs').readFileSync('tools/pricing/models.json','utf8'))\"",
|
|
36
47
|
"postinstall": "node scripts/postinstall.js",
|
|
37
48
|
"preuninstall": "node scripts/preuninstall.js",
|
|
38
49
|
"test": "vitest run",
|
|
@@ -46,14 +57,14 @@
|
|
|
46
57
|
"format:check": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\""
|
|
47
58
|
},
|
|
48
59
|
"devDependencies": {
|
|
49
|
-
"@changesets/cli": "^2.31.0",
|
|
50
60
|
"@eslint/js": "^9.39.4",
|
|
61
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
51
62
|
"@types/node": "^22.10.5",
|
|
52
63
|
"@types/proper-lockfile": "^4.1.4",
|
|
53
64
|
"@types/react": "^19.2.14",
|
|
54
65
|
"@types/react-dom": "^19.2.3",
|
|
55
66
|
"@vitejs/plugin-react": "^6.0.1",
|
|
56
|
-
"@vitest/coverage-v8": "^3.
|
|
67
|
+
"@vitest/coverage-v8": "^3.2.7",
|
|
57
68
|
"eslint": "^9.20.0",
|
|
58
69
|
"prettier": "^3.4.2",
|
|
59
70
|
"react": "^19.2.6",
|
|
@@ -65,7 +76,7 @@
|
|
|
65
76
|
"typescript-eslint": "^8.24.1",
|
|
66
77
|
"vite": "^8.0.12",
|
|
67
78
|
"vite-plugin-singlefile": "^2.3.3",
|
|
68
|
-
"vitest": "^3.
|
|
79
|
+
"vitest": "^3.2.7"
|
|
69
80
|
},
|
|
70
81
|
"publishConfig": {
|
|
71
82
|
"access": "public"
|
|
@@ -74,6 +85,13 @@
|
|
|
74
85
|
"@clack/prompts": "^1.4.0",
|
|
75
86
|
"@hono/node-server": "^2.0.2",
|
|
76
87
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
88
|
+
"@titan-design/cluster": "^0.1.0",
|
|
89
|
+
"@titan-design/daemon": "^0.1.2",
|
|
90
|
+
"@titan-design/locator": "^0.1.0",
|
|
91
|
+
"@titan-design/registry": "^0.1.0",
|
|
92
|
+
"@titan-design/session-graph": "^0.3.1",
|
|
93
|
+
"@titan-design/session-read": "^0.2.0",
|
|
94
|
+
"better-sqlite3": "^13.0.2",
|
|
77
95
|
"commander": "^14.0.3",
|
|
78
96
|
"env-paths": "^4.0.0",
|
|
79
97
|
"gray-matter": "^4.0.3",
|
|
@@ -84,5 +102,10 @@
|
|
|
84
102
|
"proper-lockfile": "^4.1.2",
|
|
85
103
|
"yaml": "^2.9.0",
|
|
86
104
|
"zod": "^4.4.3"
|
|
105
|
+
},
|
|
106
|
+
"pnpm": {
|
|
107
|
+
"onlyBuiltDependencies": [
|
|
108
|
+
"better-sqlite3"
|
|
109
|
+
]
|
|
87
110
|
}
|
|
88
111
|
}
|
|
@@ -10,20 +10,41 @@
|
|
|
10
10
|
* Requires `pnpm build` to have run so `dist/cli.js` exists.
|
|
11
11
|
*/
|
|
12
12
|
import { spawnSync } from 'node:child_process';
|
|
13
|
-
import { writeFileSync, existsSync } from 'node:fs';
|
|
13
|
+
import { writeFileSync, existsSync, statSync, readdirSync } from 'node:fs';
|
|
14
14
|
import { fileURLToPath } from 'node:url';
|
|
15
|
-
import { dirname, resolve } from 'node:path';
|
|
15
|
+
import { dirname, resolve, join } from 'node:path';
|
|
16
16
|
|
|
17
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
18
|
const REPO_ROOT = resolve(__dirname, '..');
|
|
19
19
|
const CLI = resolve(REPO_ROOT, 'dist/cli.js');
|
|
20
20
|
const OUT = resolve(REPO_ROOT, 'docs/cli-reference.md');
|
|
21
|
+
const SRC = resolve(REPO_ROOT, 'src');
|
|
21
22
|
|
|
22
23
|
if (!existsSync(CLI)) {
|
|
23
24
|
console.error(`error: ${CLI} not found. Run \`pnpm build\` first.`);
|
|
24
25
|
process.exit(1);
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
/** Recursively find the most recent mtime among files under `dir`. */
|
|
29
|
+
function newestMtime(dir) {
|
|
30
|
+
let newest = 0;
|
|
31
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
32
|
+
const path = join(dir, entry.name);
|
|
33
|
+
const mtime = entry.isDirectory() ? newestMtime(path) : statSync(path).mtimeMs;
|
|
34
|
+
if (mtime > newest) newest = mtime;
|
|
35
|
+
}
|
|
36
|
+
return newest;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const distMtime = statSync(CLI).mtimeMs;
|
|
40
|
+
const srcMtime = newestMtime(SRC);
|
|
41
|
+
if (srcMtime > distMtime) {
|
|
42
|
+
console.error(
|
|
43
|
+
`error: ${CLI} is older than src/ (dist stale). Run \`pnpm build:cli\` before regenerating docs.`,
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
27
48
|
/** Run the built CLI and return its stdout (help is written to stdout by commander). */
|
|
28
49
|
function runHelp(args) {
|
|
29
50
|
const result = spawnSync(process.execPath, [CLI, ...args, '--help'], {
|
package/skill/SKILL.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: active-work
|
|
3
3
|
description: |
|
|
4
|
-
Maintain durable per-initiative workspace state (brief,
|
|
4
|
+
Maintain durable per-initiative workspace state (brief, tasks, sessions, notes, artifacts) so engineering work picks up cleanly across Claude Code sessions. Use when the user mentions: "active work", "what am I working on", "bootstrap session", "new initiative", "record this session", "update handoff", "archive initiative", "check active", "audit my workstreams", "find untracked work", "set up active-work", "add a task", "mark X done", "what's blocking me", "wrap up", "I'm done", or types /active-work.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# active-work — durable workspace state across Claude sessions
|
|
8
8
|
|
|
9
|
-
`active-work` keeps a small filesystem-backed record for every engineering initiative the user has in flight. Files live under
|
|
9
|
+
`active-work` keeps a small filesystem-backed record for every engineering initiative the user has in flight. Files live under the active root (`~/Library/Application Support/active-work/<slug>/` on macOS — resolved via `env-paths`, which ignores `XDG_DATA_HOME`) and include `brief.md` (frontmatter + prose), `tasks/*.yml`, `sessions/*.md`, `artifacts.yml`, and `sources/` (including `sources/notes/` for durable notes). There is no `handoff.md`: current state is *derived* from the open-loop ledger in the session files, so it cannot go stale. The CLI is `active-work`; `aw <slug>` is a thin launcher that bootstraps a Claude session for an initiative. A long-running daemon, `active-work mcp serve`, exposes MCP tools to Claude Code over HTTP and serves a read-only dashboard at `http://127.0.0.1:7400/ui`.
|
|
10
10
|
|
|
11
11
|
## When to engage
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ Engage whenever the user signals they want to inspect, mutate, or hand off persi
|
|
|
16
16
|
- "bootstrap session" / `/active-work` — load the bootstrap prompt for an initiative
|
|
17
17
|
- "new initiative" — scaffold a slug with `active-work new`
|
|
18
18
|
- "add a task" / "mark X done" / "what's blocking me" — task ops via `active-work task`
|
|
19
|
-
- "record this session" / "update handoff" / "wrap up" / "I'm done" — session capture
|
|
19
|
+
- "record this session" / "update handoff" / "wrap up" / "I'm done" — session capture via `active-work wrap` (there is no handoff file; the phrase still means wrap)
|
|
20
20
|
- "archive initiative" — move a slug to the archived state
|
|
21
21
|
- "check active" / "audit my workstreams" — `active-work audit` health check
|
|
22
22
|
- "find untracked work" — `active-work discover` across configured sources
|
|
@@ -24,26 +24,62 @@ Engage whenever the user signals they want to inspect, mutate, or hand off persi
|
|
|
24
24
|
|
|
25
25
|
## Core rules
|
|
26
26
|
|
|
27
|
-
1. **Edits route through the CLI.** Use `active-work new`, `active-work set`, `active-work task add`, `active-work task done`, `active-work artifact add`, etc. Direct `Edit`/`Write` on `tasks/*.yml`, `artifacts.yml`, or the frontmatter of `brief.md` bypasses validation and corrupts the schema. Prose bodies (`brief.md` body,
|
|
27
|
+
1. **Edits route through the CLI.** Use `active-work new`, `active-work set`, `active-work task add`, `active-work task done`, `active-work artifact add`, etc. Direct `Edit`/`Write` on `tasks/*.yml`, `artifacts.yml`, or the frontmatter of `brief.md` bypasses validation and corrupts the schema. Prose bodies (`brief.md` body, session summaries, note bodies) can be edited directly, but prefer `active-work edit` for `brief.md` because it re-validates frontmatter on save.
|
|
28
28
|
2. **LLM writes prose; CLI handles structure.** Task ordering, session filenames, frontmatter dates, slug normalization, and rank reflow are CLI primitives. Don't compute them yourself.
|
|
29
29
|
3. **`active-work --help` is the canonical command reference.** This skill intentionally doesn't duplicate the surface; run `active-work --help` or `active-work <command> --help` when you need flags.
|
|
30
|
-
4. **
|
|
30
|
+
4. **Wrap is the end of the world.** See "Wrapping a session" below. This is the rule agents most often get wrong, and getting it wrong loses the user's work.
|
|
31
31
|
5. **`active-work mcp status` first.** If MCP tools aren't responding, the daemon may not be running. Start it with `active-work mcp serve --detach` before retrying.
|
|
32
32
|
|
|
33
|
+
## Wrapping a session
|
|
34
|
+
|
|
35
|
+
**Assume the process exits the instant `wrap` returns, and that everything not written to disk is lost.** Not summarized in chat — *written*. The user will very likely start a fresh session immediately; the only thing that survives is what is on disk. Chat scrollback does not carry over.
|
|
36
|
+
|
|
37
|
+
The failure this is designed to prevent: an agent posts its session summary, then follows it with two to four "oh, by the way" items — a task that should be filed, a gotcha worth remembering, an uncommitted worktree — each of which then has to be captured before the session can actually end. **Do that sweep before calling `wrap`, not after.** If you find yourself about to write "one more thing" after wrapping, you wrapped too early.
|
|
38
|
+
|
|
39
|
+
Run `active-work preflight <slug>` first. It is read-only and returns the live git state plus the checklist of categories you must answer.
|
|
40
|
+
|
|
41
|
+
Then sweep your own session for everything durable and file it:
|
|
42
|
+
|
|
43
|
+
| What you have | Where it goes |
|
|
44
|
+
|---|---|
|
|
45
|
+
| Unfinished work, open PRs, unanswered questions | `--next-steps` (the open-loop ledger) |
|
|
46
|
+
| Prior loops this session closed | `--resolves` with `outcome: done` |
|
|
47
|
+
| A thread you're deliberately dropping | `--resolves` with `outcome: abandoned` **and a note saying why** — the note is required, and it surfaces in the bootstrap for 14 days so nobody proposes the dropped thing again |
|
|
48
|
+
| Anything actionable | `active-work task add` before wrapping, then `--tasks-filed` |
|
|
49
|
+
| Process improvements, gotchas, "avoid this next time", non-actionable FYIs | `--notes` (lands in `sources/notes/`, indexed in every future bootstrap) |
|
|
50
|
+
| Uncommitted work, unpushed branches, stashes, worktree state | recorded automatically by `wrap`; add `holding` context if the bare fact isn't enough |
|
|
51
|
+
|
|
52
|
+
Write `--next-steps` text that does **not** restate the task or PR the loop targets — put the id in the step's `ref` field and let the text open with the action. The bootstrap prefixes the ref itself, so text of "AW-28 drain the miner backlog" filed against `ref: AW-28` renders as "AW-28 AW-28 drain the miner backlog" in every future session (AW-71).
|
|
53
|
+
|
|
54
|
+
Every category needs an **explicit** answer. Omitting a flag is an error, not a shortcut — the assert-nothing forms (`--no-loops`, `--no-notes`, `--no-tasks`) exist so that "there was nothing here" is a claim you make deliberately rather than by forgetting. Use them only when they are actually true.
|
|
55
|
+
|
|
56
|
+
**active-work is the source of truth — not `~/.claude` memory, not `CLAUDE.md`.** A process lesson written to memory is invisible to the next session on this initiative and to every other surface. File it as a note.
|
|
57
|
+
|
|
58
|
+
Then report back plainly: the counts of what was filed and updated, and that you are ready to end. `wrap` returns exactly that receipt — relay it rather than re-deriving it.
|
|
59
|
+
|
|
60
|
+
Check `ready_to_end` before you say you are done. It is `false` when a `--resolves` ref closed no loop; `resolves_rejected[]` names each bad ref and why. The session file and `brief.updated` are already written, so **do not re-run `wrap`** — that would duplicate the narrative. Report the rejected refs to the user; they get re-filed from a later session.
|
|
61
|
+
|
|
62
|
+
Auto-prompt the wrap when you detect the user winding down ("I'm done", "let's stop", "wrap up", inactivity after a chunk of work).
|
|
63
|
+
|
|
33
64
|
## Bootstrap flow (`aw <slug>` / `active-work open <slug>`)
|
|
34
65
|
|
|
35
|
-
`aw <slug>` is the operator-facing launcher: it assembles the bootstrap prompt and execs `claude` with the initiative's worktree as cwd. Omit the slug and it resolves the initiative from the caller's cwd (matching against each
|
|
66
|
+
`aw <slug>` is the operator-facing launcher: it assembles the bootstrap prompt and execs `claude` with the initiative's worktree as cwd. Omit the slug and it resolves the initiative from the caller's cwd (matching against each initiative's **registered** worktrees — the entries in `artifacts.yml` that carry a `name`, not the ones `wrap` merely swept), falling back to the interactive picker when nothing matches uniquely; `aw --pick` forces the picker. (Register a worktree so this resolution works with `active-work worktree set <slug> <path>`, or at creation via `new --worktree` / `track --worktree`.) `active-work open <slug>` is the same assembly logic, but prints the prompt to stdout instead of spawning Claude — use it from MCP / scripts / any caller that wants to handle the spawn itself (pass `--cwd <dir>` when the caller's process cwd isn't the user's shell cwd, e.g. the daemon). The bootstrap prompt inlines:
|
|
36
67
|
|
|
37
|
-
-
|
|
38
|
-
-
|
|
68
|
+
- A brief excerpt (the brief's prose body, truncated to 40 lines)
|
|
69
|
+
- **Open loops** — unresolved `next_steps` from prior sessions, with the age of each hang
|
|
70
|
+
- **Abandoned loops** from the last 14 days, each with the reason it was dropped (`active-work loops <slug> --state abandoned` for the full history)
|
|
39
71
|
- The most recent session summary
|
|
40
72
|
- The top N open tasks (rank-sorted)
|
|
73
|
+
- Recently-done tasks from the last 14 days, if any
|
|
74
|
+
- **Durable notes** — newest first, capped by count and never expired by age
|
|
41
75
|
- Open artifacts with status
|
|
42
|
-
-
|
|
76
|
+
- A context block with today's date, bootstrap time, and time since the last session
|
|
43
77
|
|
|
44
78
|
To re-seed context **mid-session** (a session that wasn't started via `aw`, or one that has drifted), run `active-work prompt` — it prints the same bootstrap prompt to stdout, cwd-resolved and side-effect-free (no auto-archive). The bundled `/aw-prompt` slash command wraps it and injects the output straight into the session.
|
|
45
79
|
|
|
46
|
-
|
|
80
|
+
The brief excerpt is already in your context, so **do not re-read `brief.md`** at the top of the session. Current state needs no separate file — it is the open-loop section, derived fresh at every bootstrap from the session ledger. Jump straight to the highest-rank open task unless the user redirects you. If the user opens a slug without further instruction, ask "continue with `<top task title>`?" and proceed on confirmation.
|
|
81
|
+
|
|
82
|
+
**Sibling sessions** (`# Another session may already be live on this initiative`): each bootstrap records a lease under `<active root>/.sessions/<slug>/` and warns when another session still holds one. A session launched via `aw` is reported as a live process — its pid is actually checked — while one bootstrapped through `open`/MCP is a 90-minute guess and is worded as one, because that path leaves no process to confirm. When the section appears, **ask the user which session owns the top task before starting it**. If yours is the second session, take distinct scope and record it with `active-work wrap --track adhoc`: a `canonical` wrap here buries the other session's mainline thread in the next bootstrap. When the initiative carries an agent-chat channel, also register under a name that distinguishes you and coordinate scope there. `--no-sibling-check` skips the probe on `open`/`prompt` (and, for `open`, the lease write); `--offline` skips it too. `active-work prompt` detects siblings but never records a lease of its own — it stays read-only. Dead leases are swept at the next bootstrap; `active-work doctor` reports the live/pruned counts.
|
|
47
83
|
|
|
48
84
|
**Ad-hoc sessions** (`aw <slug> --adhoc`, also `open`/`prompt --adhoc`): the opening and closing directives change to say the session is scoped to ad-hoc work on the workstream — the context is background, *not* a directive. Do **not** offer to continue the top task; wait for the user to describe the specific ad-hoc task, then work it with the workstream context in mind. The bootstrap prompt itself carries this instruction, so follow whichever framing it renders.
|
|
49
85
|
|
|
@@ -46,7 +46,7 @@ active-work track gh:hjewkes/active-work#42 \
|
|
|
46
46
|
--title "Dashboard load is sluggish on cold open"
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
`active-work track` scaffolds the initiative (`brief.md` with frontmatter, empty `
|
|
49
|
+
`active-work track` scaffolds the initiative (`brief.md` with frontmatter, empty `tasks/`, an `artifacts.yml` seeded with the source ref), then prints the new slug. Open it next:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
52
|
active-work open dashboard-perf
|
|
@@ -82,15 +82,13 @@ After triage, run the audit to catch issues:
|
|
|
82
82
|
active-work audit
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
`audit` is a cross-initiative summary, not a rule engine. It returns exactly three things:
|
|
86
86
|
|
|
87
|
-
-
|
|
88
|
-
-
|
|
89
|
-
- `
|
|
90
|
-
- Last session timestamp isn't stale beyond the configured threshold
|
|
91
|
-
- No frontmatter validation errors
|
|
87
|
+
- `initiatives` — every slug with its title, state, rank, `updated` date, and ship target, sorted by rank then state
|
|
88
|
+
- `parse_errors` — slugs whose `brief.md` frontmatter failed validation, with the error
|
|
89
|
+
- `worktree_conflicts` — worktree paths registered by more than one initiative
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
For per-initiative health checks — staleness, loops hanging past 30 days, dangling `next_steps` refs — use `active-work lint` and `active-work doctor` instead. Nothing here is fatal; fix findings with `active-work set <slug> ...`, `active-work task add`, or `active-work archive`.
|
|
94
92
|
|
|
95
93
|
## Worked example
|
|
96
94
|
|
|
@@ -118,8 +116,14 @@ $ active-work drop claude:session/0192abc --reason "one-off debugging, no follow
|
|
|
118
116
|
dropped
|
|
119
117
|
|
|
120
118
|
$ active-work audit
|
|
121
|
-
|
|
122
|
-
|
|
119
|
+
{
|
|
120
|
+
"initiatives": [
|
|
121
|
+
{ "slug": "dashboard-perf", "title": "Dashboard cold-load perf", "state": "focused", "rank": 1, "updated": "2026-07-28" },
|
|
122
|
+
{ "slug": "brain-inbox-rewrite", "title": "Brain inbox rewrite", "state": "focused", "rank": 2, "updated": "2026-07-28" }
|
|
123
|
+
],
|
|
124
|
+
"parse_errors": [],
|
|
125
|
+
"worktree_conflicts": []
|
|
126
|
+
}
|
|
123
127
|
```
|
|
124
128
|
|
|
125
129
|
The user is now caught up. Continue with `active-work open dashboard-perf` (or whichever slug they want to push on first).
|
|
@@ -19,6 +19,7 @@ If you are modifying the `active-work` skill, adding a CLI command, extending th
|
|
|
19
19
|
| `src/templates/` | Mustache templates for scaffolding new initiatives. |
|
|
20
20
|
| `src/bootstrap/` | Bootstrap prompt assembly used by `active-work open`. |
|
|
21
21
|
| `src/discover/` | Discovery sources (gh, git, projects, Claude sessions). |
|
|
22
|
+
| `src/sources/` | Reads `<slug>/sources/*.md` at call time. There is no sidecar index and no `sources:` frontmatter field — a stored list drifts from the directory, so the listing is always derived. |
|
|
22
23
|
| `skill/` | This skill. Copied into `~/.claude/skills/active-work/` by `scripts/postinstall.js`. |
|
|
23
24
|
| `scripts/` | npm lifecycle hooks: `postinstall.js`, `preuninstall.js`. |
|
|
24
25
|
| `__tests__/` | Vitest tests; fixtures under `__tests__/fixtures/`. |
|
|
@@ -26,7 +27,7 @@ If you are modifying the `active-work` skill, adding a CLI command, extending th
|
|
|
26
27
|
## Adding a new command
|
|
27
28
|
|
|
28
29
|
1. Create `src/commands/<name>.ts` exporting a `defineCommand({...})` entry. Define:
|
|
29
|
-
- `name` (e.g. `"task
|
|
30
|
+
- `name` (dot-separated, e.g. `"task.add"`)
|
|
30
31
|
- `description`
|
|
31
32
|
- `input` zod schema
|
|
32
33
|
- `output` zod schema
|
|
@@ -46,7 +47,7 @@ If you are modifying the `active-work` skill, adding a CLI command, extending th
|
|
|
46
47
|
`src/server/` runs hono on `127.0.0.1:7400` by default (override with `AW_PORT`). It serves:
|
|
47
48
|
|
|
48
49
|
- `/rpc/<command>` — REST for every registry entry
|
|
49
|
-
- `/
|
|
50
|
+
- `/events` — SSE live-reload feed (`hono/streaming`), backed by a hand-rolled recursive `fs.watch` in `src/server/file-watch.ts` (not WebSocket, not chokidar), debounced and broadcast via `EventHub`
|
|
50
51
|
- `/mcp` — MCP-over-HTTP transport
|
|
51
52
|
- `/ui` — bundled dashboard SPA
|
|
52
53
|
|
|
@@ -36,19 +36,15 @@ ls ~/.claude/skills/active-work/
|
|
|
36
36
|
|
|
37
37
|
## 4. Run `active-work setup`
|
|
38
38
|
|
|
39
|
-
`active-work setup` (Wave 6) is the interactive wizard that initializes data roots, registers the MCP server with Claude Code, and offers to install the daemon launchd plist. **It is not yet implemented.** Until it lands, you can prepare the data root manually:
|
|
40
|
-
|
|
41
39
|
```bash
|
|
42
|
-
|
|
40
|
+
active-work setup
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
(
|
|
43
|
+
This is the interactive wizard: it checks your Node version, creates the active/state/config data roots, writes a config stub, installs the skill and the `/aw-prompt` command (idempotently — safe to re-run), registers the MCP server with Claude Code (`claude mcp add --user @hjewkes/active-work -- active-work mcp serve --stdio`), offers to install daemon supervision (launchd on macOS, systemd with linger on Linux), offers to start the daemon, and offers to walk through discovering existing work.
|
|
46
44
|
|
|
47
|
-
|
|
45
|
+
Use `active-work setup --yes` for a non-interactive run (skips prompts, assumes no for daemon start), or `--update` to allow it to overwrite an existing config stub.
|
|
48
46
|
|
|
49
|
-
|
|
50
|
-
claude mcp add --user @hjewkes/active-work -- active-work mcp serve --stdio
|
|
51
|
-
```
|
|
47
|
+
If the `claude` CLI isn't on your PATH, the MCP-registration step prints the `~/.claude.json` snippet to add by hand instead of failing.
|
|
52
48
|
|
|
53
49
|
## 5. Verify the install
|
|
54
50
|
|
|
@@ -61,7 +57,7 @@ active-work mcp status # reports daemon state
|
|
|
61
57
|
|
|
62
58
|
## 6. Optional — start the daemon
|
|
63
59
|
|
|
64
|
-
The daemon hosts MCP-over-HTTP, the REST API,
|
|
60
|
+
The daemon hosts MCP-over-HTTP, the REST API, an SSE live-reload feed (`/events`), and the dashboard.
|
|
65
61
|
|
|
66
62
|
```bash
|
|
67
63
|
active-work mcp serve --detach
|