waypoint-codex 0.7.0 → 0.8.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 CHANGED
@@ -22,10 +22,12 @@ Waypoint scaffolds a Codex-friendly repo structure built around a few core piece
22
22
 
23
23
  - `AGENTS.md` for the startup contract
24
24
  - `.waypoint/WORKSPACE.md` for live operational state
25
+ - `.waypoint/track/` for active long-running execution trackers
25
26
  - `.waypoint/docs/` for durable project memory
26
27
  - `.waypoint/DOCS_INDEX.md` for docs routing
28
+ - `.waypoint/TRACKS_INDEX.md` for tracker routing
27
29
  - `.waypoint/context/` for generated startup context
28
- - `.agents/skills/` for repo-local workflows like planning, audits, and QA
30
+ - `.agents/skills/` for repo-local workflows like planning, tracking, audits, and QA
29
31
 
30
32
  The philosophy is simple:
31
33
 
@@ -40,7 +42,7 @@ Waypoint is most useful when you want:
40
42
 
41
43
  - multi-session continuity in a real repo
42
44
  - a durable docs and workspace structure for agents
43
- - stronger planning, review, QA, and closeout defaults
45
+ - stronger planning, tracking, review, QA, and closeout defaults
44
46
  - repo-local scaffolding instead of a bunch of global mystery behavior
45
47
 
46
48
  If you only use Codex for tiny one-off edits, Waypoint is probably unnecessary.
@@ -76,9 +78,11 @@ repo/
76
78
  ├── .agents/
77
79
  │ └── skills/
78
80
  └── .waypoint/
79
- ├── WORKSPACE.md
80
81
  ├── DOCS_INDEX.md
82
+ ├── TRACKS_INDEX.md
83
+ ├── WORKSPACE.md
81
84
  ├── docs/
85
+ ├── track/
82
86
  ├── context/
83
87
  ├── scripts/
84
88
  └── ...
@@ -126,9 +130,7 @@ Flags you can combine:
126
130
  Waypoint ships a strong default skill pack for real coding work:
127
131
 
128
132
  - `planning`
129
- - `error-audit`
130
- - `observability-audit`
131
- - `ux-states-audit`
133
+ - `work-tracker`
132
134
  - `docs-sync`
133
135
  - `code-guide-audit`
134
136
  - `break-it-qa`
package/dist/src/core.js CHANGED
@@ -4,14 +4,18 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import * as TOML from "@iarna/toml";
6
6
  import { renderDocsIndex } from "./docs-index.js";
7
+ import { renderTracksIndex } from "./track-index.js";
7
8
  import { readTemplate, renderWaypointConfig, MANAGED_BLOCK_END, MANAGED_BLOCK_START, templatePath } from "./templates.js";
8
9
  const DEFAULT_CONFIG_PATH = ".waypoint/config.toml";
9
10
  const DEFAULT_DOCS_DIR = ".waypoint/docs";
10
11
  const DEFAULT_DOCS_INDEX = ".waypoint/DOCS_INDEX.md";
12
+ const DEFAULT_TRACK_DIR = ".waypoint/track";
13
+ const DEFAULT_TRACKS_INDEX = ".waypoint/TRACKS_INDEX.md";
11
14
  const DEFAULT_WORKSPACE = ".waypoint/WORKSPACE.md";
12
15
  const STATE_DIR = ".waypoint/state";
13
16
  const SYNC_RECORDS_FILE = ".waypoint/state/sync-records.json";
14
17
  const TIMESTAMPED_WORKSPACE_SECTIONS = new Set([
18
+ "## Active Trackers",
15
19
  "## Current State",
16
20
  "## In Progress",
17
21
  "## Next",
@@ -101,6 +105,7 @@ function scaffoldWaypointOptionalTemplates(projectRoot) {
101
105
  copyTemplateTree(templatePath(".waypoint/automations"), path.join(projectRoot, ".waypoint/automations"));
102
106
  copyTemplateTree(templatePath(".waypoint/rules"), path.join(projectRoot, ".waypoint/rules"));
103
107
  copyTemplateTree(templatePath(".waypoint/scripts"), path.join(projectRoot, ".waypoint/scripts"));
108
+ copyTemplateTree(templatePath(".waypoint/track"), path.join(projectRoot, ".waypoint/track"));
104
109
  }
105
110
  function scaffoldOptionalCodex(projectRoot) {
106
111
  copyTemplateTree(templatePath(".codex"), path.join(projectRoot, ".codex"));
@@ -112,6 +117,9 @@ export function initRepository(projectRoot, options) {
112
117
  "docs/README.md",
113
118
  "docs/code-guide.md",
114
119
  "docs/legacy-import",
120
+ ".agents/skills/error-audit",
121
+ ".agents/skills/observability-audit",
122
+ ".agents/skills/ux-states-audit",
115
123
  "WAYPOINT_MIGRATION.md",
116
124
  ".agents/skills/waypoint-planning",
117
125
  ".agents/skills/waypoint-docs",
@@ -145,6 +153,7 @@ export function initRepository(projectRoot, options) {
145
153
  }));
146
154
  writeIfMissing(path.join(projectRoot, DEFAULT_WORKSPACE), readTemplate("WORKSPACE.md"));
147
155
  ensureDir(path.join(projectRoot, DEFAULT_DOCS_DIR));
156
+ ensureDir(path.join(projectRoot, DEFAULT_TRACK_DIR));
148
157
  writeIfMissing(path.join(projectRoot, ".waypoint/docs/README.md"), readTemplate(".waypoint/docs/README.md"));
149
158
  writeIfMissing(path.join(projectRoot, ".waypoint/docs/code-guide.md"), readTemplate(".waypoint/docs/code-guide.md"));
150
159
  upsertManagedBlock(path.join(projectRoot, "AGENTS.md"), readTemplate("managed-agents-block.md"));
@@ -154,13 +163,15 @@ export function initRepository(projectRoot, options) {
154
163
  }
155
164
  appendGitignoreSnippet(projectRoot);
156
165
  const docsIndex = renderDocsIndex(projectRoot, path.join(projectRoot, DEFAULT_DOCS_DIR));
166
+ const tracksIndex = renderTracksIndex(projectRoot, path.join(projectRoot, DEFAULT_TRACK_DIR));
157
167
  writeText(path.join(projectRoot, DEFAULT_DOCS_INDEX), `${docsIndex.content}\n`);
168
+ writeText(path.join(projectRoot, DEFAULT_TRACKS_INDEX), `${tracksIndex.content}\n`);
158
169
  return [
159
170
  "Initialized Waypoint scaffold",
160
171
  "Installed managed AGENTS block",
161
- "Created .waypoint/WORKSPACE.md and .waypoint/docs/ scaffold",
172
+ "Created .waypoint/WORKSPACE.md, .waypoint/docs/, and .waypoint/track/ scaffold",
162
173
  "Installed repo-local Waypoint skills",
163
- "Generated .waypoint/DOCS_INDEX.md",
174
+ "Generated .waypoint/DOCS_INDEX.md and .waypoint/TRACKS_INDEX.md",
164
175
  ];
165
176
  }
166
177
  export function loadWaypointConfig(projectRoot) {
@@ -366,6 +377,7 @@ export function doctorRepository(projectRoot) {
366
377
  const workspaceText = readFileSync(workspacePath, "utf8");
367
378
  for (const section of [
368
379
  "## Active Goal",
380
+ "## Active Trackers",
369
381
  "## Current State",
370
382
  "## In Progress",
371
383
  "## Next",
@@ -398,6 +410,7 @@ export function doctorRepository(projectRoot) {
398
410
  path.join(projectRoot, ".waypoint", "agent-operating-manual.md"),
399
411
  path.join(projectRoot, ".waypoint", "scripts", "prepare-context.mjs"),
400
412
  path.join(projectRoot, ".waypoint", "scripts", "build-docs-index.mjs"),
413
+ path.join(projectRoot, ".waypoint", "scripts", "build-track-index.mjs"),
401
414
  ]) {
402
415
  if (!existsSync(requiredFile)) {
403
416
  findings.push({
@@ -412,6 +425,9 @@ export function doctorRepository(projectRoot) {
412
425
  const docsDir = path.join(projectRoot, config.docs_dir ?? DEFAULT_DOCS_DIR);
413
426
  const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
414
427
  const docsIndex = renderDocsIndex(projectRoot, docsDir);
428
+ const trackDir = path.join(projectRoot, DEFAULT_TRACK_DIR);
429
+ const tracksIndexPath = path.join(projectRoot, DEFAULT_TRACKS_INDEX);
430
+ const tracksIndex = renderTracksIndex(projectRoot, trackDir);
415
431
  if (!existsSync(docsDir)) {
416
432
  findings.push({
417
433
  severity: "error",
@@ -448,11 +464,56 @@ export function doctorRepository(projectRoot) {
448
464
  paths: [docsIndexPath],
449
465
  });
450
466
  }
467
+ if (!existsSync(trackDir)) {
468
+ findings.push({
469
+ severity: "error",
470
+ category: "track",
471
+ message: ".waypoint/track/ directory is missing.",
472
+ remediation: "Run `waypoint init` to scaffold track files.",
473
+ paths: [trackDir],
474
+ });
475
+ }
476
+ for (const relPath of tracksIndex.invalidTracks) {
477
+ findings.push({
478
+ severity: "warn",
479
+ category: "track",
480
+ message: `Tracker is missing valid frontmatter or status: ${relPath}`,
481
+ remediation: "Add `summary`, `last_updated`, `status`, and `read_when` frontmatter using the track template.",
482
+ paths: [path.join(projectRoot, relPath)],
483
+ });
484
+ }
485
+ if (!existsSync(tracksIndexPath)) {
486
+ findings.push({
487
+ severity: "warn",
488
+ category: "track",
489
+ message: ".waypoint/TRACKS_INDEX.md is missing.",
490
+ remediation: "Run `waypoint sync` to generate the tracks index.",
491
+ paths: [tracksIndexPath],
492
+ });
493
+ }
494
+ else if (readFileSync(tracksIndexPath, "utf8").trimEnd() !== tracksIndex.content.trimEnd()) {
495
+ findings.push({
496
+ severity: "warn",
497
+ category: "track",
498
+ message: ".waypoint/TRACKS_INDEX.md is stale.",
499
+ remediation: "Run `waypoint sync` to rebuild the tracks index.",
500
+ paths: [tracksIndexPath],
501
+ });
502
+ }
503
+ if (existsSync(workspacePath) &&
504
+ tracksIndex.activeTrackPaths.length > 0 &&
505
+ !tracksIndex.activeTrackPaths.some((trackPath) => readFileSync(workspacePath, "utf8").includes(trackPath))) {
506
+ findings.push({
507
+ severity: "warn",
508
+ category: "track",
509
+ message: "Workspace does not reference any active tracker file.",
510
+ remediation: "Add the active `.waypoint/track/*.md` file paths under `## Active Trackers` in `.waypoint/WORKSPACE.md`.",
511
+ paths: [workspacePath, ...tracksIndex.activeTrackPaths.map((trackPath) => path.join(projectRoot, trackPath))],
512
+ });
513
+ }
451
514
  for (const skillName of [
452
515
  "planning",
453
- "error-audit",
454
- "observability-audit",
455
- "ux-states-audit",
516
+ "work-tracker",
456
517
  "docs-sync",
457
518
  "code-guide-audit",
458
519
  "break-it-qa",
@@ -528,8 +589,12 @@ export function syncRepository(projectRoot) {
528
589
  const docsDir = path.join(projectRoot, config.docs_dir ?? DEFAULT_DOCS_DIR);
529
590
  const docsIndexPath = path.join(projectRoot, config.docs_index_file ?? DEFAULT_DOCS_INDEX);
530
591
  const docsIndex = renderDocsIndex(projectRoot, docsDir);
592
+ const trackDir = path.join(projectRoot, DEFAULT_TRACK_DIR);
593
+ const tracksIndexPath = path.join(projectRoot, DEFAULT_TRACKS_INDEX);
594
+ const tracksIndex = renderTracksIndex(projectRoot, trackDir);
531
595
  writeText(docsIndexPath, `${docsIndex.content}\n`);
532
- const results = ["Rebuilt .waypoint/DOCS_INDEX.md"];
596
+ writeText(tracksIndexPath, `${tracksIndex.content}\n`);
597
+ const results = ["Rebuilt .waypoint/DOCS_INDEX.md", "Rebuilt .waypoint/TRACKS_INDEX.md"];
533
598
  const featureMap = config.features ?? {};
534
599
  if (featureMap.rules) {
535
600
  results.push(...syncRules(projectRoot));
@@ -0,0 +1,107 @@
1
+ import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
2
+ import path from "node:path";
3
+ const VALID_TRACK_STATUSES = new Set(["active", "blocked", "paused", "done", "archived"]);
4
+ const ACTIVE_TRACK_STATUSES = new Set(["active", "blocked", "paused"]);
5
+ const SKIP_NAMES = new Set(["README.md", "CHANGELOG.md", "LICENSE.md"]);
6
+ function shouldSkipTrackFile(entry) {
7
+ return SKIP_NAMES.has(entry) || entry.startsWith("_");
8
+ }
9
+ function parseFrontmatter(filePath) {
10
+ const text = readFileSync(filePath, "utf8");
11
+ if (!text.startsWith("---\n")) {
12
+ return { summary: "", lastUpdated: "", readWhen: [], status: "" };
13
+ }
14
+ const endIndex = text.indexOf("\n---\n", 4);
15
+ if (endIndex === -1) {
16
+ return { summary: "", lastUpdated: "", readWhen: [], status: "" };
17
+ }
18
+ const frontmatter = text.slice(4, endIndex);
19
+ let summary = "";
20
+ let lastUpdated = "";
21
+ let status = "";
22
+ const readWhen = [];
23
+ let collectingReadWhen = false;
24
+ for (const rawLine of frontmatter.split("\n")) {
25
+ const line = rawLine.trim();
26
+ if (line.startsWith("summary:")) {
27
+ summary = line.slice("summary:".length).trim().replace(/^['"]|['"]$/g, "");
28
+ collectingReadWhen = false;
29
+ continue;
30
+ }
31
+ if (line.startsWith("last_updated:")) {
32
+ lastUpdated = line.slice("last_updated:".length).trim().replace(/^['"]|['"]$/g, "");
33
+ collectingReadWhen = false;
34
+ continue;
35
+ }
36
+ if (line.startsWith("status:")) {
37
+ status = line.slice("status:".length).trim().replace(/^['"]|['"]$/g, "").toLowerCase();
38
+ collectingReadWhen = false;
39
+ continue;
40
+ }
41
+ if (line.startsWith("read_when:")) {
42
+ collectingReadWhen = true;
43
+ continue;
44
+ }
45
+ if (collectingReadWhen && line.startsWith("- ")) {
46
+ readWhen.push(line.slice(2).trim());
47
+ continue;
48
+ }
49
+ if (collectingReadWhen && line.length > 0) {
50
+ collectingReadWhen = false;
51
+ }
52
+ }
53
+ return { summary, lastUpdated, readWhen, status };
54
+ }
55
+ function walkTracks(projectRoot, currentDir, output, invalid) {
56
+ for (const entry of readdirSync(currentDir)) {
57
+ const fullPath = path.join(currentDir, entry);
58
+ const stat = statSync(fullPath);
59
+ if (stat.isDirectory()) {
60
+ walkTracks(projectRoot, fullPath, output, invalid);
61
+ continue;
62
+ }
63
+ if (!entry.endsWith(".md") || shouldSkipTrackFile(entry)) {
64
+ continue;
65
+ }
66
+ const { summary, lastUpdated, readWhen, status } = parseFrontmatter(fullPath);
67
+ const relPath = path.relative(projectRoot, fullPath);
68
+ if (!summary || !lastUpdated || readWhen.length === 0 || !VALID_TRACK_STATUSES.has(status)) {
69
+ invalid.push(relPath);
70
+ continue;
71
+ }
72
+ output.push({ path: relPath, summary, readWhen, status });
73
+ }
74
+ }
75
+ export function renderTracksIndex(projectRoot, trackDir) {
76
+ const entries = [];
77
+ const invalidTracks = [];
78
+ if (existsSync(trackDir)) {
79
+ walkTracks(projectRoot, trackDir, entries, invalidTracks);
80
+ }
81
+ const lines = [
82
+ "# Tracks Index",
83
+ "",
84
+ "Auto-generated by `waypoint sync` / `waypoint doctor`. Read active trackers when resuming long-running work.",
85
+ "",
86
+ "## .waypoint/track/",
87
+ "",
88
+ ];
89
+ if (entries.length === 0) {
90
+ lines.push("No tracker files found.");
91
+ }
92
+ else {
93
+ for (const entry of entries.sort((a, b) => a.path.localeCompare(b.path))) {
94
+ lines.push(`- **${entry.path}** — [${entry.status}] ${entry.summary}`);
95
+ lines.push(` Read when: ${entry.readWhen.join("; ")}`);
96
+ }
97
+ }
98
+ lines.push("");
99
+ return {
100
+ content: `${lines.join("\n")}`,
101
+ invalidTracks,
102
+ activeTrackPaths: entries
103
+ .filter((entry) => ACTIVE_TRACK_STATUSES.has(entry.status))
104
+ .map((entry) => entry.path)
105
+ .sort((a, b) => a.localeCompare(b)),
106
+ };
107
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waypoint-codex",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Codex-native repository operating system: scaffolding, docs routing, repo-local skills, doctor, and sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -47,6 +47,8 @@ Skip rules that genuinely do not apply, but say that you skipped them.
47
47
 
48
48
  This skill is narrower than `pre-pr-hygiene`. Use that other skill for broader ship-readiness.
49
49
 
50
+ If this audit produces a large remediation campaign, create or update a tracker under `.waypoint/track/` before switching into implementation so the fix list does not live only in chat.
51
+
50
52
  ## Step 4: Verify Evidence
51
53
 
52
54
  Ground each finding in the actual code.
@@ -36,6 +36,8 @@ The plan belongs in the repo, not only in chat.
36
36
  - Make sure the doc remains discoverable through the routed docs layer.
37
37
  - In chat, return only a concise summary plus the path to the plan doc.
38
38
 
39
+ If the planned implementation will be large, multi-step, or likely to span multiple sessions, also create or update a tracker under `.waypoint/track/` and link it from `WORKSPACE.md` before implementation begins.
40
+
39
41
  ## The Core Loop
40
42
 
41
43
  ```
@@ -0,0 +1,110 @@
1
+ ---
2
+ name: work-tracker
3
+ description: Create or maintain a durable tracker under `.waypoint/track/` for large multi-step work. Use when implementation will span multiple sessions, when an audit or review produces many fix items, when verification has a long checklist, or whenever `WORKSPACE.md` would become too detailed if it tried to hold the whole execution log.
4
+ ---
5
+
6
+ # Work Tracker
7
+
8
+ Use this skill when the work is too large, too long-running, or too itemized to live safely in `WORKSPACE.md`.
9
+
10
+ This skill owns the execution tracker layer:
11
+
12
+ - create or update `.waypoint/track/<slug>.md`
13
+ - keep `WORKSPACE.md` pointing at the active tracker
14
+ - move detailed checklists and progress into the tracker instead of bloating the workspace
15
+
16
+ ## Read First
17
+
18
+ Before tracking:
19
+
20
+ 1. Read `.waypoint/SOUL.md`
21
+ 2. Read `.waypoint/agent-operating-manual.md`
22
+ 3. Read `.waypoint/WORKSPACE.md`
23
+ 4. Read `.waypoint/context/MANIFEST.md`
24
+ 5. Read every file listed in that manifest
25
+ 6. Read `.waypoint/track/README.md`
26
+
27
+ ## When A Tracker Is Required
28
+
29
+ Create or update a tracker when any of these are true:
30
+
31
+ - the work will likely span multiple sessions
32
+ - there are many actionable items to implement
33
+ - an audit, QA pass, or review produced a remediation campaign
34
+ - verification requires a substantial checklist
35
+ - `WORKSPACE.md` would become noisy if it carried all the detail
36
+
37
+ Small, single-shot work does not need a tracker.
38
+
39
+ ## Step 1: Choose The Tracker File
40
+
41
+ - Use `.waypoint/track/<kebab-case-slug>.md`.
42
+ - If a relevant tracker already exists, update it instead of creating a competing one.
43
+ - Keep one tracker per coherent workstream, not one tracker per tiny edit.
44
+
45
+ ## Step 2: Set The Frontmatter
46
+
47
+ Trackers need:
48
+
49
+ ```yaml
50
+ ---
51
+ summary: One-line description
52
+ last_updated: "2026-03-13 11:38 PDT"
53
+ status: active
54
+ read_when:
55
+ - resuming this workstream
56
+ ---
57
+ ```
58
+
59
+ Valid statuses:
60
+
61
+ - `active`
62
+ - `blocked`
63
+ - `paused`
64
+ - `done`
65
+ - `archived`
66
+
67
+ Use `active` unless there is a clear reason not to.
68
+
69
+ ## Step 3: Structure The Tracker
70
+
71
+ A good tracker usually includes:
72
+
73
+ - `Goal`
74
+ - `Source`
75
+ - `Current State`
76
+ - `Next`
77
+ - `Workstreams`
78
+ - `Verification`
79
+ - `Decisions`
80
+ - `Notes`
81
+
82
+ Use checklists when there are many concrete items. Use timestamped bullets for materially revised state.
83
+
84
+ ## Step 4: Link It From The Workspace
85
+
86
+ Add or update a bullet under `## Active Trackers` in `.waypoint/WORKSPACE.md` that points at the tracker path and states the current phase or next step.
87
+
88
+ `WORKSPACE.md` should answer "what matters right now?"
89
+ The tracker should answer "what exactly is happening across the whole workstream?"
90
+
91
+ ## Step 5: Maintain It During Execution
92
+
93
+ - Update `last_updated` whenever you materially change the tracker.
94
+ - Mark completed items done instead of deleting the record.
95
+ - Add blockers, new tasks, and verification status as the work evolves.
96
+ - When the workstream finishes, set `status: done` or `status: archived`.
97
+
98
+ Do not let the tracker become fiction. It must match reality.
99
+
100
+ ## Step 6: Distill Durable Knowledge
101
+
102
+ If the tracker reveals durable architecture, rollout, or debugging knowledge, move that durable knowledge into `.waypoint/docs/` and leave the tracker focused on execution state.
103
+
104
+ ## Report
105
+
106
+ When you create or update a tracker, report:
107
+
108
+ - the tracker path
109
+ - the current status
110
+ - what `WORKSPACE.md` now points to
@@ -39,6 +39,7 @@ Ask one question:
39
39
 
40
40
  Keep only the answer to that question in the workspace. Usually that means:
41
41
 
42
+ - active tracker pointers
42
43
  - current focus
43
44
  - latest verified state
44
45
  - open blockers or risks
@@ -52,6 +53,7 @@ Usually remove or collapse:
52
53
  - validation transcripts
53
54
  - old milestone history
54
55
  - duplicated durable documentation
56
+ - per-item implementation checklists that belong in `.waypoint/track/`
55
57
 
56
58
  Compression is documentation quality, not data loss.
57
59
 
@@ -66,6 +68,7 @@ When editing the workspace:
66
68
  5. Do not turn the workspace into an archive, changelog, or debug notebook.
67
69
 
68
70
  If durable context is missing from `.waypoint/docs/`, add or refresh the smallest coherent routed doc before removing it from the workspace.
71
+ If execution detail is still active but too large for the workspace, move it into `.waypoint/track/` instead of deleting it.
69
72
 
70
73
  ## Step 4: Protect User-Owned State
71
74
 
@@ -33,8 +33,9 @@ Do not skip this sequence.
33
33
  The repository should contain the context the next agent needs.
34
34
 
35
35
  - `.waypoint/WORKSPACE.md` is the live operational record: in progress, current state, next steps
36
+ - `.waypoint/track/` is the durable execution-tracking layer for active long-running work
36
37
  - `.waypoint/docs/` is the durable project memory: architecture, decisions, integration notes, debugging knowledge, and durable plans
37
- - `.waypoint/context/` is the generated session context bundle: current git/PR/doc index state
38
+ - `.waypoint/context/` is the generated session context bundle: current git/PR/doc/track index state
38
39
 
39
40
  If something important lives only in your head or in the chat transcript, the repo is under-documented.
40
41
 
@@ -43,8 +44,10 @@ If something important lives only in your head or in the chat transcript, the re
43
44
  - Read code before editing it.
44
45
  - Follow the repo's documented patterns when they are healthy.
45
46
  - Update `.waypoint/WORKSPACE.md` as live execution state when progress meaningfully changes. In multi-topic sections, prefix new or materially revised bullets with a local timestamp like `[2026-03-06 20:10 PST]`.
47
+ - For large multi-step work, create or update a tracker in `.waypoint/track/`, keep detailed execution state there, and point at it from `## Active Trackers` in `.waypoint/WORKSPACE.md`.
46
48
  - Update `.waypoint/docs/` when durable knowledge changes, and refresh each changed routable doc's `last_updated` field.
47
49
  - Rebuild `.waypoint/DOCS_INDEX.md` whenever routable docs change.
50
+ - Rebuild `.waypoint/TRACKS_INDEX.md` whenever tracker files change.
48
51
  - Use the repo-local skills and optional reviewer agents instead of improvising from scratch.
49
52
  - Do not kill long-running subagents or reviewer agents just because they are slow. Wait unless they are clearly stuck, failed, or the user redirects the work.
50
53
 
@@ -64,9 +67,7 @@ Do not document every trivial implementation detail. Document the non-obvious, d
64
67
  ## When to use Waypoint skills
65
68
 
66
69
  - `planning` for non-trivial changes
67
- - `error-audit` when failures are being swallowed or degraded invisibly
68
- - `observability-audit` when production debugging signals look weak
69
- - `ux-states-audit` when async/data-driven UI likely lacks loading, empty, or error states
70
+ - `work-tracker` when large multi-step work needs durable progress tracking in `.waypoint/track/`
70
71
  - `docs-sync` when routed docs may be stale, missing, or inconsistent with the codebase
71
72
  - `code-guide-audit` when a specific feature or file set needs a targeted coding-guide compliance check
72
73
  - `break-it-qa` when a browser-facing feature should be attacked with invalid inputs, refreshes, repeated clicks, wrong action order, or other adversarial manual QA
@@ -13,6 +13,8 @@ Put the durable context here that the next agent will need to continue the work:
13
13
 
14
14
  These are **project docs**, not Waypoint internals.
15
15
 
16
+ Do not use `.waypoint/docs/` as the execution tracker layer for active long-running work. That belongs under `.waypoint/track/`.
17
+
16
18
  Every routable doc needs YAML frontmatter:
17
19
 
18
20
  ```yaml
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const VALID_TRACK_STATUSES = new Set(["active", "blocked", "paused", "done", "archived"]);
8
+ const ACTIVE_TRACK_STATUSES = new Set(["active", "blocked", "paused"]);
9
+ const SKIP_NAMES = new Set(["README.md", "CHANGELOG.md", "LICENSE.md"]);
10
+
11
+ export function findProjectRoot(startDir) {
12
+ let current = path.resolve(startDir);
13
+ while (true) {
14
+ if (existsSync(path.join(current, ".waypoint", "config.toml"))) {
15
+ return current;
16
+ }
17
+ const parent = path.dirname(current);
18
+ if (parent === current) {
19
+ return path.resolve(startDir);
20
+ }
21
+ current = parent;
22
+ }
23
+ }
24
+
25
+ function detectProjectRoot() {
26
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
27
+ const scriptBasedRoot = findProjectRoot(path.resolve(scriptDir, "../.."));
28
+ if (existsSync(path.join(scriptBasedRoot, ".waypoint", "config.toml"))) {
29
+ return scriptBasedRoot;
30
+ }
31
+ return findProjectRoot(process.cwd());
32
+ }
33
+
34
+ function shouldSkipTrackFile(entry) {
35
+ return SKIP_NAMES.has(entry) || entry.startsWith("_");
36
+ }
37
+
38
+ function parseFrontmatter(filePath) {
39
+ const text = readFileSync(filePath, "utf8");
40
+ if (!text.startsWith("---\n")) {
41
+ return { summary: "", lastUpdated: "", readWhen: [], status: "" };
42
+ }
43
+
44
+ const endIndex = text.indexOf("\n---\n", 4);
45
+ if (endIndex === -1) {
46
+ return { summary: "", lastUpdated: "", readWhen: [], status: "" };
47
+ }
48
+
49
+ const frontmatter = text.slice(4, endIndex);
50
+ let summary = "";
51
+ let lastUpdated = "";
52
+ let status = "";
53
+ const readWhen = [];
54
+ let collectingReadWhen = false;
55
+
56
+ for (const rawLine of frontmatter.split("\n")) {
57
+ const line = rawLine.trim();
58
+ if (line.startsWith("summary:")) {
59
+ summary = line.slice("summary:".length).trim().replace(/^['"]|['"]$/g, "");
60
+ collectingReadWhen = false;
61
+ continue;
62
+ }
63
+ if (line.startsWith("last_updated:")) {
64
+ lastUpdated = line.slice("last_updated:".length).trim().replace(/^['"]|['"]$/g, "");
65
+ collectingReadWhen = false;
66
+ continue;
67
+ }
68
+ if (line.startsWith("status:")) {
69
+ status = line.slice("status:".length).trim().replace(/^['"]|['"]$/g, "").toLowerCase();
70
+ collectingReadWhen = false;
71
+ continue;
72
+ }
73
+ if (line.startsWith("read_when:")) {
74
+ collectingReadWhen = true;
75
+ continue;
76
+ }
77
+ if (collectingReadWhen && line.startsWith("- ")) {
78
+ readWhen.push(line.slice(2).trim());
79
+ continue;
80
+ }
81
+ if (collectingReadWhen && line.length > 0) {
82
+ collectingReadWhen = false;
83
+ }
84
+ }
85
+
86
+ return { summary, lastUpdated, readWhen, status };
87
+ }
88
+
89
+ function walkTracks(projectRoot, currentDir, output, invalid) {
90
+ for (const entry of readdirSync(currentDir)) {
91
+ const fullPath = path.join(currentDir, entry);
92
+ const stat = statSync(fullPath);
93
+ if (stat.isDirectory()) {
94
+ walkTracks(projectRoot, fullPath, output, invalid);
95
+ continue;
96
+ }
97
+
98
+ if (!entry.endsWith(".md") || shouldSkipTrackFile(entry)) {
99
+ continue;
100
+ }
101
+
102
+ const { summary, lastUpdated, readWhen, status } = parseFrontmatter(fullPath);
103
+ if (!summary || !lastUpdated || readWhen.length === 0 || !VALID_TRACK_STATUSES.has(status)) {
104
+ invalid.push(path.relative(projectRoot, fullPath));
105
+ continue;
106
+ }
107
+
108
+ output.push({
109
+ path: path.relative(projectRoot, fullPath),
110
+ summary,
111
+ readWhen,
112
+ status,
113
+ });
114
+ }
115
+ }
116
+
117
+ export function renderTracksIndex(projectRoot) {
118
+ const trackDir = path.join(projectRoot, ".waypoint", "track");
119
+ const entries = [];
120
+ const invalidTracks = [];
121
+
122
+ if (existsSync(trackDir)) {
123
+ walkTracks(projectRoot, trackDir, entries, invalidTracks);
124
+ }
125
+
126
+ const lines = [
127
+ "# Tracks Index",
128
+ "",
129
+ "Auto-generated by `.waypoint/scripts/build-track-index.mjs`. Read active trackers when resuming long-running work.",
130
+ "",
131
+ "## .waypoint/track/",
132
+ "",
133
+ ];
134
+
135
+ if (entries.length === 0) {
136
+ lines.push("No tracker files found.");
137
+ } else {
138
+ entries.sort((a, b) => a.path.localeCompare(b.path));
139
+ for (const entry of entries) {
140
+ lines.push(`- **${entry.path}** — [${entry.status}] ${entry.summary}`);
141
+ lines.push(` Read when: ${entry.readWhen.join("; ")}`);
142
+ }
143
+ }
144
+
145
+ lines.push("");
146
+ return {
147
+ content: `${lines.join("\n")}\n`,
148
+ invalidTracks,
149
+ activeTracks: entries
150
+ .filter((entry) => ACTIVE_TRACK_STATUSES.has(entry.status))
151
+ .map((entry) => entry.path)
152
+ .sort((a, b) => a.localeCompare(b)),
153
+ };
154
+ }
155
+
156
+ export function writeTracksIndex(projectRoot) {
157
+ const outputPath = path.join(projectRoot, ".waypoint", "TRACKS_INDEX.md");
158
+ const rendered = renderTracksIndex(projectRoot);
159
+ writeFileSync(outputPath, rendered.content, "utf8");
160
+ return { outputPath, activeTracks: rendered.activeTracks, invalidTracks: rendered.invalidTracks };
161
+ }
162
+
163
+ const isDirectExecution = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
164
+
165
+ if (isDirectExecution) {
166
+ const projectRoot = detectProjectRoot();
167
+ const { outputPath } = writeTracksIndex(projectRoot);
168
+ console.log(`Wrote ${outputPath}`);
169
+ }
@@ -7,6 +7,7 @@ import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
9
  import { findProjectRoot, writeDocsIndex } from "./build-docs-index.mjs";
10
+ import { writeTracksIndex } from "./build-track-index.mjs";
10
11
 
11
12
  const __filename = fileURLToPath(import.meta.url);
12
13
  const __dirname = path.dirname(__filename);
@@ -437,6 +438,21 @@ function writeContextFile(contextDir, name, title, body) {
437
438
  return filePath;
438
439
  }
439
440
 
441
+ function writeActiveTrackers(contextDir, projectRoot, activeTracks) {
442
+ return writeContextFile(
443
+ contextDir,
444
+ "ACTIVE_TRACKERS.md",
445
+ "Active Trackers",
446
+ activeTracks.length === 0
447
+ ? "No active tracker files found."
448
+ : [
449
+ "These trackers should be read when resuming long-running work:",
450
+ "",
451
+ ...activeTracks.map((trackPath) => `- \`${trackPath}\``),
452
+ ].join("\n"),
453
+ );
454
+ }
455
+
440
456
  function main() {
441
457
  const projectRoot = detectProjectRoot();
442
458
  const contextDir = path.join(projectRoot, ".waypoint", "context");
@@ -448,6 +464,7 @@ function main() {
448
464
  : null;
449
465
 
450
466
  const docsIndexPath = writeDocsIndex(projectRoot);
467
+ const { outputPath: tracksIndexPath, activeTracks } = writeTracksIndex(projectRoot);
451
468
 
452
469
  const currentDatetimePath = writeContextFile(
453
470
  contextDir,
@@ -590,6 +607,7 @@ function main() {
590
607
  ].join("\n")
591
608
  );
592
609
  const recentThreadPath = writeRecentThread(contextDir, projectRoot, threadIdOverride);
610
+ const activeTrackersPath = writeActiveTrackers(contextDir, projectRoot, activeTracks);
593
611
 
594
612
  const manifestPath = path.join(contextDir, "MANIFEST.md");
595
613
  const manifestLines = [
@@ -606,6 +624,8 @@ function main() {
606
624
  `- \`${path.relative(projectRoot, prsPath)}\` — open and recently merged pull requests`,
607
625
  `- \`${path.relative(projectRoot, recentThreadPath)}\` — latest meaningful turns from the local Codex session for this repo`,
608
626
  `- \`${path.relative(projectRoot, docsIndexPath)}\` — current docs index`,
627
+ `- \`${path.relative(projectRoot, tracksIndexPath)}\` — current tracker index`,
628
+ `- \`${path.relative(projectRoot, activeTrackersPath)}\` — active tracker summary`,
609
629
  "",
610
630
  "## Stable source-of-truth files to read before this manifest",
611
631
  "",
@@ -613,6 +633,10 @@ function main() {
613
633
  "- `.waypoint/agent-operating-manual.md`",
614
634
  "- `.waypoint/WORKSPACE.md`",
615
635
  "",
636
+ "## Active tracker files to read after this manifest",
637
+ "",
638
+ ...(activeTracks.length > 0 ? activeTracks.map((trackPath) => `- \`${trackPath}\``) : ["- None."]),
639
+ "",
616
640
  `Generated by: \`${path.relative(projectRoot, fileURLToPath(import.meta.url))}\``,
617
641
  "",
618
642
  ];
@@ -0,0 +1,38 @@
1
+ # Waypoint Trackers
2
+
3
+ This directory holds active execution trackers for long-running work.
4
+
5
+ Use `.waypoint/track/` when the work is too large to fit safely in `WORKSPACE.md`, especially for:
6
+
7
+ - multi-session implementation campaigns
8
+ - broad audits followed by remediation
9
+ - large fix lists or rollout work
10
+ - verification or review loops that will take time to close
11
+
12
+ Tracker files are **execution state**, not general project memory.
13
+
14
+ - Keep durable architecture, decisions, and long-term reference material in `.waypoint/docs/`.
15
+ - Keep `WORKSPACE.md` short and current.
16
+ - Put detailed checklists, per-item status, blockers, and verification progress in `.waypoint/track/`.
17
+
18
+ Every tracker needs YAML frontmatter:
19
+
20
+ ```yaml
21
+ ---
22
+ summary: One-line description
23
+ last_updated: "2026-03-13 11:38 PDT"
24
+ status: active
25
+ read_when:
26
+ - resuming the workstream
27
+ ---
28
+ ```
29
+
30
+ Valid tracker statuses:
31
+
32
+ - `active`
33
+ - `blocked`
34
+ - `paused`
35
+ - `done`
36
+ - `archived`
37
+
38
+ `WORKSPACE.md` should point at the active tracker file under `## Active Trackers`.
@@ -0,0 +1,44 @@
1
+ ---
2
+ summary: One-line description of the workstream
3
+ last_updated: "2026-03-13 11:38 PDT"
4
+ status: active
5
+ read_when:
6
+ - resuming this workstream
7
+ ---
8
+
9
+ # Tracker Title
10
+
11
+ ## Goal
12
+
13
+ What outcome this tracker is trying to reach.
14
+
15
+ ## Source
16
+
17
+ - User request, audit, plan, or review thread that kicked off the work.
18
+
19
+ ## Current State
20
+
21
+ - [2026-03-13 11:38 PDT] Current truth about the work.
22
+
23
+ ## Next
24
+
25
+ - [2026-03-13 11:38 PDT] The next concrete action.
26
+
27
+ ## Workstreams
28
+
29
+ ### 1. Stream Name
30
+
31
+ - [ ] First task
32
+ - [ ] Second task
33
+
34
+ ## Verification
35
+
36
+ - [ ] Verification step
37
+
38
+ ## Decisions
39
+
40
+ - [2026-03-13 11:38 PDT] Decision and rationale.
41
+
42
+ ## Notes
43
+
44
+ - Useful details that do not belong in `WORKSPACE.md`.
@@ -1,11 +1,15 @@
1
1
  # Workspace
2
2
 
3
- Timestamp discipline: Prefix new or materially revised bullets in `Current State`, `In Progress`, `Next`, `Parked`, and `Done Recently` with `[YYYY-MM-DD HH:MM TZ]`.
3
+ Timestamp discipline: Prefix new or materially revised bullets in `Active Trackers`, `Current State`, `In Progress`, `Next`, `Parked`, and `Done Recently` with `[YYYY-MM-DD HH:MM TZ]`.
4
4
 
5
5
  ## Active Goal
6
6
 
7
7
  Describe the main thing currently being built or changed.
8
8
 
9
+ ## Active Trackers
10
+
11
+ List any active tracker docs under `.waypoint/track/`, with the current phase or next step.
12
+
9
13
  ## Current State
10
14
 
11
15
  What is already true right now?
@@ -32,8 +32,10 @@ This is mandatory, not optional.
32
32
 
33
33
  Working rules:
34
34
  - Keep `.waypoint/WORKSPACE.md` current as the live execution state, with timestamped new or materially revised entries in multi-topic sections
35
+ - For large multi-step work, create or update `.waypoint/track/<slug>.md`, keep detailed execution state there, and point to it from `## Active Trackers` in `.waypoint/WORKSPACE.md`
35
36
  - Update `.waypoint/docs/` when behavior or durable project knowledge changes, and refresh `last_updated` on touched routable docs
36
37
  - Use the repo-local skills Waypoint ships for structured workflows when relevant
38
+ - Use `work-tracker` when a long-running implementation, remediation, or verification campaign needs durable progress tracking
37
39
  - Use `docs-sync` when the docs may be stale or a change altered shipped behavior, contracts, routes, or commands
38
40
  - Use `code-guide-audit` for a targeted coding-guide compliance pass on a specific feature, file set, or change slice
39
41
  - Use `break-it-qa` for browser-facing features that should be tested against invalid inputs, refreshes, repeated clicks, wrong navigation, and other adversarial user behavior
@@ -1,69 +0,0 @@
1
- ---
2
- name: error-audit
3
- description: Audit code for silent error swallowing, fallbacks to degraded alternatives, backwards compatibility shims, and UI that fails to show errors to the user. Finds and fixes all occurrences in the specified scope.
4
- ---
5
-
6
- # Error Audit
7
-
8
- The core principle: **every error belongs to the user**. Not to a catch block, not to a console, not to a null return. Scan the specified code, fix every violation, report what changed.
9
-
10
- ## Read First
11
-
12
- 1. Read `.waypoint/SOUL.md`
13
- 2. Read `.waypoint/agent-operating-manual.md`
14
- 3. Read `WORKSPACE.md`
15
- 4. Read `.waypoint/context/MANIFEST.md`
16
- 5. Read every file listed in the manifest
17
- 6. Read `references/error-patterns.md`
18
-
19
- ## Step 0: Understand the app's error mechanisms
20
-
21
- Before fixing anything, identify how this app surfaces errors to users — toast notifications, error banners, error boundaries, returned error states, alert dialogs, inline messages. Use these patterns exclusively. Don't invent a new one.
22
-
23
- ## Anti-patterns to find and fix
24
-
25
- **Silent error swallowing — backend/logic layer:**
26
- - Empty catch blocks: `catch(e) {}`
27
- - Log-and-continue with execution proceeding normally
28
- - `.catch(() => {})` on promises
29
- - Functions returning `null`, `undefined`, or empty defaults on failure instead of throwing
30
-
31
- **Silent error swallowing — UI layer:**
32
- - Data fetching catches an error and returns null/empty -> component renders blank with no explanation
33
- - Error boundaries that catch but show nothing (or a generic "something went wrong" with no recovery path)
34
- - `try/catch` in a loader or server action that swallows the error and returns partial/empty data
35
- - Async operations where the UI has no error state at all — success renders fine, failure renders identical to loading or empty
36
-
37
- **Fallbacks to degraded alternatives:**
38
- - Catch -> silently switch to a worse model, API, or service
39
- - Catch -> return cached or stale data without telling the user
40
- - Catch -> offline/degraded mode with no visible indication
41
-
42
- **Backwards compatibility shims:**
43
- - `if (legacyFormat)` or `if (oldVersion)` branches
44
- - Deprecated fields still being populated alongside new ones
45
- - Old code paths running in parallel with new ones
46
-
47
- **Config defaults that hide misconfiguration:**
48
- - `process.env.X || 'fallback'` for required values — missing required config is a startup crash, not a default
49
- - Optional environment variables that should be required
50
-
51
- **Optional chaining hiding missing required data:**
52
- - `user?.profile?.name ?? 'Guest'` when profile must always exist — the absence is a bug, not an edge case to handle silently
53
-
54
- ## Fix principles
55
-
56
- - Throw or re-throw rather than catch-and-continue
57
- - In the UI: every error path must render something visible — use the app's established error display mechanism
58
- - Required config missing at startup -> log a clear message and exit
59
- - Delete fallback branches — don't comment them out
60
- - When unsure if a fallback was intentional, flag it in your report rather than guessing
61
-
62
- ## Reference files
63
-
64
- - `references/error-patterns.md` — Concrete anti-patterns with structural descriptions, examples, and false positive notes. Read this before starting the audit.
65
-
66
- ## Report
67
-
68
- After fixing, summarize by file: what was found, what the fix was. Be specific — file paths and the pattern removed.
69
-
@@ -1,37 +0,0 @@
1
- # Error Anti-Patterns Reference
2
-
3
- Patterns to identify when auditing error handling. Each section describes the anti-pattern structurally — what the code does, not just what keywords to grep for.
4
-
5
- ## Silent error swallowing
6
-
7
- - empty catch blocks
8
- - `.catch(() => {})`
9
- - broad exception handlers that return defaults
10
- - ignored Go errors via `_`
11
-
12
- ## Log-and-continue
13
-
14
- An error gets logged, but execution continues as if the operation succeeded.
15
-
16
- ## Return-null-on-failure
17
-
18
- The function converts a real operational failure into what looks like a normal "empty" result.
19
-
20
- ## Invisible degradation
21
-
22
- The code silently falls back to a worse model, API, cache, or degraded mode with no visible signal.
23
-
24
- ## Config defaults hiding misconfiguration
25
-
26
- Required settings should fail loudly, not silently pick a fallback.
27
-
28
- ## UI error blindness
29
-
30
- Failure should not render the same as loading or empty.
31
-
32
- Quality bar:
33
-
34
- - confirm the issue is real in context
35
- - prefer concrete fixes over broad rewrites
36
- - use existing repo patterns for user-visible error handling
37
-
@@ -1,67 +0,0 @@
1
- ---
2
- name: observability-audit
3
- description: Audit code for observability gaps — debug logs left in, errors caught without being logged, missing context on log entries, and untracked slow operations. Uses the app's existing observability tooling exclusively.
4
- ---
5
-
6
- # Observability Audit
7
-
8
- Code that works locally but is impossible to debug in production. This skill finds and fixes observability gaps using whatever tools the app already has.
9
-
10
- ## Read First
11
-
12
- 1. Read `.waypoint/SOUL.md`
13
- 2. Read `.waypoint/agent-operating-manual.md`
14
- 3. Read `WORKSPACE.md`
15
- 4. Read `.waypoint/context/MANIFEST.md`
16
- 5. Read every file listed in the manifest
17
- 6. Read `references/observability-patterns.md`
18
-
19
- ## Step 0: Research existing observability tooling
20
-
21
- Before anything else, explore the codebase to understand what's already in use:
22
-
23
- - Error tracking
24
- - Logging
25
- - APM / metrics
26
- - Analytics
27
- - Any custom logger or telemetry utilities
28
-
29
- Read how they're configured and how they're used. All fixes must use these — never introduce a new observability dependency or pattern.
30
-
31
- ## What to look for
32
-
33
- **Debug artifacts left in production code**
34
-
35
- **Errors that disappear**
36
-
37
- **Missing context on log entries**
38
-
39
- **Untracked slow or critical operations**
40
-
41
- See `references/observability-patterns.md` for concrete patterns.
42
-
43
- ## Process
44
-
45
- 1. Research existing tooling
46
- 2. Identify the scope
47
- 3. Find every instance of the anti-patterns
48
- 4. Fix using the existing tooling and patterns
49
- 5. Remove debug artifacts, add context to thin logs, add tracking where missing
50
- 6. Report changes
51
-
52
- ## Fix principles
53
-
54
- - Every caught error should be logged with enough context to reproduce the problem
55
- - Use the existing logger/tracker — never introduce a second one
56
- - Debug `console.log` goes away entirely — no conversion to structured log, just deleted
57
- - Log context should include: what operation, what failed, relevant IDs
58
- - Don't add logging to every function — focus on boundaries and critical paths
59
-
60
- ## Reference files
61
-
62
- - `references/observability-patterns.md` — Detection patterns, bad/fix examples for debug artifacts, missing logging, missing context, untracked operations. Read before starting the audit.
63
-
64
- ## Report
65
-
66
- Summarize by file: what was removed, what was added or improved, what context was missing and is now included.
67
-
@@ -1,35 +0,0 @@
1
- # Observability Anti-Patterns Reference
2
-
3
- Use this file to guide observability audits.
4
-
5
- ## Debug artifacts
6
-
7
- - `console.log`, `console.debug`, `print`, `fmt.Printf` in non-CLI production paths
8
- - commented-out debug statements
9
- - `debugger` and focused tests left behind
10
-
11
- ## Errors without useful traces
12
-
13
- - catch/except blocks that rethrow or return without logging context
14
- - tracker calls with no metadata
15
- - logs that say "failed" without saying what failed
16
-
17
- ## Missing context
18
-
19
- - no user, entity, request, or job identifiers
20
- - no operation name
21
- - no correlation/request ID at service boundaries
22
-
23
- ## Slow paths with no timing
24
-
25
- - external API calls
26
- - critical database queries
27
- - background jobs without start/complete/fail visibility
28
- - webhook handlers with no event-level logging
29
-
30
- Quality bar:
31
-
32
- - use the existing observability stack
33
- - improve debugging value, not log volume
34
- - focus on boundaries and critical paths
35
-
@@ -1,63 +0,0 @@
1
- ---
2
- name: ux-states-audit
3
- description: Audit UI code for missing loading states, empty states, and error states. Every async operation and data-driven UI must handle all three. Finds gaps and implements the missing states using the app's existing patterns.
4
- ---
5
-
6
- # UX States Audit
7
-
8
- Every piece of UI that fetches data or triggers async work has three states beyond the happy path: **loading**, **empty**, and **error**. LLMs implement the happy path and leave the rest blank. This skill finds and fills those gaps.
9
-
10
- This is distinct from `error-audit`: `error-audit` finds errors that are suppressed. This finds states that were never implemented.
11
-
12
- ## Read First
13
-
14
- 1. Read `.waypoint/SOUL.md`
15
- 2. Read `.waypoint/agent-operating-manual.md`
16
- 3. Read `WORKSPACE.md`
17
- 4. Read `.waypoint/context/MANIFEST.md`
18
- 5. Read every file listed in the manifest
19
- 6. Read `references/ux-patterns.md`
20
-
21
- ## Step 0: Understand existing patterns
22
-
23
- Before touching anything, read the codebase to understand how it currently handles these states:
24
-
25
- - loading components or primitives
26
- - empty state patterns
27
- - error display patterns
28
-
29
- Use these patterns exclusively. Don't introduce a new loading spinner if one already exists.
30
-
31
- ## What to look for
32
-
33
- **Missing loading state**
34
-
35
- **Missing empty state**
36
-
37
- **Missing error state**
38
-
39
- See `references/ux-patterns.md` for concrete patterns.
40
-
41
- ## Process
42
-
43
- 1. Identify the scope
44
- 2. Find every component that fetches data or triggers async work
45
- 3. For each: check whether loading, empty, and error states are handled
46
- 4. Implement missing states using the patterns found in Step 0
47
- 5. Report what was added, by component
48
-
49
- ## Fix principles
50
-
51
- - Loading states should be immediate
52
- - Empty states should explain the situation and, where appropriate, offer an action
53
- - Error states should say what went wrong and what the user can do
54
- - Don't invent new UI primitives — use what already exists
55
-
56
- ## Reference files
57
-
58
- - `references/ux-patterns.md` — Detection patterns and examples for missing loading, empty, and error states. Read before starting the audit.
59
-
60
- ## Report
61
-
62
- Summarize by component: which states were missing, what was added.
63
-
@@ -1,34 +0,0 @@
1
- # UX State Patterns Reference
2
-
3
- Use this file to guide UX state audits.
4
-
5
- ## Missing loading state
6
-
7
- Look for:
8
-
9
- - fetch starts and nothing changes visually
10
- - button-triggered async action with no pending state
11
- - form submission with no disabled or in-progress signal
12
-
13
- ## Missing empty state
14
-
15
- Look for:
16
-
17
- - empty lists rendering blank space
18
- - search results with no explanation when empty
19
- - dashboard widgets vanishing instead of explaining that no data exists
20
-
21
- ## Missing error state
22
-
23
- Look for:
24
-
25
- - fetch failure rendering the same as loading
26
- - mutation failure with no user-visible feedback
27
- - components returning blank/null on failure
28
-
29
- Quality bar:
30
-
31
- - use the repo's established UI primitives
32
- - implement all three states where relevant
33
- - favor clarity over decorative treatment
34
-