Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions .claude/hooks/hub-stop.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env node
/**
* hub-stop.js — Stop hook for Work-Down managed Claude sessions.
* hub-stop.js — Stop hook for dashboard-managed Claude sessions.
*
* Only signals Hub when Work-Down specific env vars are present.
* Outside Work-Down dispatched sessions, this hook is a no-op.
* Signals the Dispatch dashboard when DISPATCH_* (or legacy HUB_*) env vars are present.
* Outside dispatched sessions, this hook is a no-op.
*/

const fs = require("fs");
Expand Down Expand Up @@ -50,9 +50,11 @@ function postJson(urlString, payload, callback) {
}

function main() {
const apiBase = process.env.HUB_API_BASE || "";
const sessionId = process.env.HUB_SESSION_ID || "";
const jobId = process.env.HUB_JOB_ID || "";
const apiBase =
process.env.DISPATCH_API_BASE || process.env.HUB_API_BASE || "";
const sessionId =
process.env.DISPATCH_SESSION_ID || process.env.HUB_SESSION_ID || "";
const jobId = process.env.DISPATCH_JOB_ID || process.env.HUB_JOB_ID || "";

if (!apiBase || !sessionId || !jobId) {
process.exit(0);
Expand Down
6 changes: 3 additions & 3 deletions .claude/skills/add-repo/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ argument-hint: [repo-name or path]
allowed-tools: Read, Write, Edit, Bash(ls *), Bash(test *), Bash(mkdir *), Bash(cp *), Bash(node *)
---

# /add-repo — Add a Repository to the Hub
# /add-repo — Add a Repository to Dispatch

Add a new repo to `config.json`, scaffold its tracking files, and install the hub completion hook so the dashboard can track dispatched jobs.

Expand All @@ -19,7 +19,7 @@ Add a new repo to `config.json`, scaffold its tracking files, and install the hu
node cli.js config
```

Note the existing repos (for duplicate detection) and the hub's resolved path (you'll need it to locate the hook file to copy).
Note the existing repos (for duplicate detection) and the dispatch root’s resolved path (you'll need it to locate the hook file to copy).

---

Expand All @@ -30,7 +30,7 @@ If `$ARGUMENTS` was provided, infer the repo name or path from it. Otherwise ask
> **To add a repo I need a few details:**
>
> 1. **Repo name** — short identifier for the dashboard (e.g. `backend`, `mobile`, `docs`)
> 2. **Path** — relative path from the hub root (e.g. `../my-backend`)
> 2. **Path** — relative path from the dispatch root (e.g. `../my-backend`)
> 3. **Start script** — command to run the dev server (e.g. `npm run dev`), or skip
> 4. **Test script** — command to run tests, or skip
> 5. **Cleanup script** — command to remove build artifacts, or skip
Expand Down
4 changes: 2 additions & 2 deletions .claude/skills/add-repo/references/formats.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ All fields except `name` and `path` are optional (use `null` if unknown).

**Field notes:**
- `name` — short identifier used in CLI output and dashboard labels. Lowercase, no spaces.
- `path` — relative path from the hub root. Always `../repo-name` for sibling repos, `.` for the hub itself.
- `path` — relative path from the dispatch root. Always `../repo-name` for sibling repos, `.` for the dispatch repo itself.
- `taskFile` — almost always `todo.md`. Only change if the repo uses a different name.
- `bugsFile` — optional. Set to `null` if the repo doesn't track bugs separately.
- `activityFile` — almost always `activity-log.md`.
- `startScript` — command to start the dev server. `null` if not applicable.
- `testScript` — command to run tests. `null` if not applicable.
- `cleanupScript` — command to clean build artifacts. `null` if not applicable.

The `hub` entry (path `.`) must always remain in the list and should not be modified.
The `dispatch` entry (path `.`) for this coordination repo must always remain in the list and should not be removed.

---

Expand Down
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ Dispatch loads configuration from:
In this checkout, **`config.local.json` is the effective source of truth** for repo paths and file locations.

Do not assume `config.json` reflects the active local repo set.

The dashboard server resolves the **dispatch root** with `DISPATCH_ROOT` (or legacy `HUB_DIR`), defaulting to the parent of `dashboard/`. Config may include **`dispatchRoot`** (camelCase JSON); legacy **`hubRoot`** is normalized to `dispatchRoot` on load.
11 changes: 6 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ Defined in `config.local.json` when present, otherwise `config.json`. In this ch
| Field | Description |
|-------|-------------|
| `name` | Short name used in CLI output and dashboard |
| `path` | Relative path from hub root to the repo |
| `path` | Relative path from dispatch root to the repo |
| `taskFile` | Markdown file for tasks (default: `todo.md`) |
| `bugsFile` | Markdown file for bugs (default: `bugs.md`) |
| `activityFile` | Markdown file for activity (default: `activity-log.md`) |
| `startScript` | Command to start the repo's dev server |
| `testScript` | Command to run tests |
| `cleanupScript` | Command to clean build artifacts |
| `color` | Optional hex string (e.g. `#8bab8f`) for dashboard repo accents in `/api/overview`, activity feed, and filters |

Every repo tracks tasks in `todo.md` and activity in `activity-log.md`.

Expand All @@ -42,12 +43,12 @@ config.json ─── loadConfig() ───┐
## Key Files

- **config.local.json** -- Effective local repo definitions for this checkout. Dispatch loads this first when present.
- **config.json** -- Fallback/shared repo definitions when `config.local.json` is absent. `hubRoot` (display path) and `monthlyBudget` (optional) are user-specific; set `hubRoot` to your local hub path (e.g. `.` for current dir). Server falls back to `HUB_DIR` env var when `hubRoot` is unset.
- **config.json** -- Fallback/shared repo definitions when `config.local.json` is absent. `dispatchRoot` (display path) and `monthlyBudget` (optional) are user-specific; set `dispatchRoot` to your local dispatch root (e.g. `.` for current dir). Dashboard server falls back to `DISPATCH_ROOT` env var when unset (legacy `HUB_DIR` is still read for compatibility). Legacy `hubRoot` in JSON is normalized to `dispatchRoot` on load.
- **parsers.js** -- CommonJS module. Primary job APIs: `parseJobFile`, `parseJobDir`, `writeJobValidation`, `writeJobKill`, `writeJobStatus`. Also owns task/activity parsing, task writes, and checkpoint helpers. Zero external dependencies.
- **cli.js** -- Agent-friendly CLI. All output is JSON to stdout, errors as JSON to stderr. Commands: `status`, `tasks [--repo=name]`, `swarm [id]`, `repos`, `activity [--limit=N]`, `config`.
- **terminal.js** -- Human-friendly ANSI terminal dashboard. Read-only display, no interactivity. Uses box-drawing characters.
- **todo.md** -- Hub's own task tracker (markdown checkboxes).
- **activity-log.md** -- Hub's own activity log. Contains `**Current stage:**` metadata.
- **todo.md** -- Dispatch root's own task tracker (markdown checkboxes).
- **activity-log.md** -- Dispatch root's own activity log. Contains `**Current stage:**` metadata.
- **notes/jobs/** -- Job progress files (gitignored — runtime artifacts). Named `YYYY-MM-DD-slug.md`.
- **.dispatch/runtime/** -- Server runtime state (gitignored): `.dispatch/runtime/job-runs.json` for job run state, `.dispatch/runtime/prompts/` for staged Claude prompts, `.dispatch/runtime/events/` for terminal event snapshots/NDJSON.

Expand Down Expand Up @@ -110,7 +111,7 @@ yarn start # Serve built SPA + API from port 3747

## Rules

1. **`config.local.json` is the source of truth when present; otherwise use `config.json`** for repo paths and file locations. In this repo, prefer `config.local.json`. Do not hardcode repo paths elsewhere.
1. **`config.local.json` is the source of truth when present; otherwise use `config.json`** for repo paths and file locations. In this repo, prefer `config.local.json`. Do not hardcode repo paths elsewhere. Use **`DISPATCH_ROOT`** (absolute path to the dispatch root) when overriding the server’s working directory; **`HUB_DIR`** is deprecated but still honored by the dashboard server.
2. **`parsers.js` is shared infrastructure.** Test changes against all three consumers (cli.js, terminal.js, dashboard/server.js) before committing.
3. **Job progress files** go in `notes/jobs/YYYY-MM-DD-slug.md` with the standard format (see Conventions above).
4. **All repos use the same task/activity pattern**: `todo.md` for tasks, `activity-log.md` for activity.
Expand Down
4 changes: 2 additions & 2 deletions cli.integration.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ let cliPath;

function setup() {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cli-int-'));
// Copy cli.js and parsers.js to tmp dir so HUB_DIR resolves to tmp
// Copy cli.js and parsers.js to tmp dir so DISPATCH_ROOT resolves to tmp
cliPath = path.join(tmpDir, 'cli.js');
fs.copyFileSync(srcCliPath, cliPath);
fs.copyFileSync(srcParsersPath, path.join(tmpDir, 'parsers.js'));
Expand Down Expand Up @@ -81,7 +81,7 @@ function createTestHub(opts = {}) {
activityFile: 'activity-log.md',
},
],
hubRoot: '.',
dispatchRoot: '.',
};
if (opts.extraRepos) config.repos.push(...opts.extraRepos);
fs.writeFileSync(path.join(hubDir, 'config.json'), JSON.stringify(config, null, 2));
Expand Down
4 changes: 2 additions & 2 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const {
createCheckpoint, revertCheckpoint, dismissCheckpoint, listCheckpoints,
} = require('./parsers');

const HUB_DIR = path.dirname(__filename);
const DISPATCH_ROOT = path.dirname(__filename);

function fail(msg) {
process.stderr.write(JSON.stringify({ error: msg }) + '\n');
Expand Down Expand Up @@ -65,7 +65,7 @@ flags._positional = positionals[0] || null;
// Load config
let config;
try {
config = loadConfig(HUB_DIR);
config = loadConfig(DISPATCH_ROOT);
} catch {
fail('config.local.json or config.json not found or invalid');
}
Expand Down
4 changes: 3 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
{
"name": "example-app",
"path": "../example-app",
"color": "#6366f1",
"taskFile": "todo.md",
"bugsFile": "bugs.md",
"activityFile": "activity-log.md",
Expand All @@ -13,6 +14,7 @@
{
"name": "dispatch",
"path": ".",
"color": "#8bab8f",
"taskFile": "todo.md",
"bugsFile": "bugs.md",
"activityFile": "activity-log.md",
Expand All @@ -21,5 +23,5 @@
"cleanupScript": "cd dashboard && rm -rf dist node_modules/.vite"
}
],
"hubRoot": "."
"dispatchRoot": "."
}
8 changes: 4 additions & 4 deletions dashboard/server.integration.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let server;
let baseUrl;

/**
* Create a test hub filesystem structure and set HUB_DIR before importing server.
* Create a test dispatch root filesystem structure and set DISPATCH_ROOT before importing server.
*/
function createTestHub() {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dash-int-'));
Expand All @@ -40,7 +40,7 @@ function createTestHub() {
activityFile: 'activity-log.md',
},
],
hubRoot: '.',
dispatchRoot: '.',
}, null, 2));

// todo.md
Expand Down Expand Up @@ -109,7 +109,7 @@ before(async () => {
const { repoDir } = createTestHub();

// Set env vars before importing server
process.env.HUB_DIR = tmpDir;
process.env.DISPATCH_ROOT = tmpDir;
process.env.TESTING = '1';

const mod = await import('./server.js');
Expand All @@ -133,7 +133,7 @@ after(async () => {
if (tmpDir) {
fs.rmSync(tmpDir, { recursive: true, force: true });
}
delete process.env.HUB_DIR;
delete process.env.DISPATCH_ROOT;
delete process.env.TESTING;
});

Expand Down
Loading
Loading