waypoint-codex 0.7.0 → 0.8.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/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
  └── ...
@@ -94,6 +98,12 @@ From there, start your Codex session in the repo and follow the generated bootst
94
98
  waypoint init
95
99
  ```
96
100
 
101
+ By default, `waypoint init` updates the global CLI to the latest published `waypoint-codex` first, then scaffolds with that fresh version. If you want to scaffold with the currently installed binary instead, use:
102
+
103
+ ```bash
104
+ waypoint init --skip-cli-update
105
+ ```
106
+
97
107
  ### Full local workflow setup
98
108
 
99
109
  ```bash
@@ -112,10 +122,11 @@ Flags you can combine:
112
122
  - `--with-roles`
113
123
  - `--with-rules`
114
124
  - `--with-automations`
125
+ - `--skip-cli-update`
115
126
 
116
127
  ## Main commands
117
128
 
118
- - `waypoint init` — scaffold or refresh the repo
129
+ - `waypoint init` — update the CLI to latest by default, then scaffold or refresh the repo
119
130
  - `waypoint doctor` — validate health and report drift
120
131
  - `waypoint sync` — rebuild the docs index and sync optional user-home artifacts
121
132
  - `waypoint upgrade` — update the CLI and refresh the current repo using its saved config
@@ -126,9 +137,7 @@ Flags you can combine:
126
137
  Waypoint ships a strong default skill pack for real coding work:
127
138
 
128
139
  - `planning`
129
- - `error-audit`
130
- - `observability-audit`
131
- - `ux-states-audit`
140
+ - `work-tracker`
132
141
  - `docs-sync`
133
142
  - `code-guide-audit`
134
143
  - `break-it-qa`
package/dist/src/cli.js CHANGED
@@ -5,7 +5,7 @@ import { fileURLToPath } from "node:url";
5
5
  import path from "node:path";
6
6
  import process from "node:process";
7
7
  import { doctorRepository, importLegacyRepo, initRepository, loadWaypointConfig, syncRepository } from "./core.js";
8
- import { upgradeWaypoint } from "./upgrade.js";
8
+ import { maybeUpgradeWaypointBeforeInit, upgradeWaypoint } from "./upgrade.js";
9
9
  const VERSION = JSON.parse(readFileSync(path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../package.json"), "utf8")).version;
10
10
  function resolveRepo(input) {
11
11
  return path.resolve(input ?? ".");
@@ -27,7 +27,7 @@ function printHelp() {
27
27
  console.log(`usage: waypoint [--version] <command> [options]
28
28
 
29
29
  Commands:
30
- init Initialize a repository with Waypoint scaffolding
30
+ init Initialize a repository with Waypoint scaffolding (auto-updates CLI unless skipped)
31
31
  doctor Validate repository health and report drift
32
32
  sync Rebuild docs index and sync optional user-home artifacts
33
33
  upgrade Update the global Waypoint CLI and refresh this repo using existing config
@@ -52,11 +52,22 @@ async function main() {
52
52
  "app-friendly": { type: "boolean", default: false },
53
53
  "with-roles": { type: "boolean", default: false },
54
54
  "with-rules": { type: "boolean", default: false },
55
- "with-automations": { type: "boolean", default: false }
55
+ "with-automations": { type: "boolean", default: false },
56
+ "skip-cli-update": { type: "boolean", default: false }
56
57
  },
57
58
  allowPositionals: true
58
59
  });
59
60
  const projectRoot = resolveRepo(positionals[0]);
61
+ if (!values["skip-cli-update"]) {
62
+ const status = maybeUpgradeWaypointBeforeInit({
63
+ currentVersion: VERSION,
64
+ cliEntry: process.argv[1] ? path.resolve(process.argv[1]) : fileURLToPath(import.meta.url),
65
+ initArgs: argv.slice(1),
66
+ });
67
+ if (status !== null) {
68
+ return status;
69
+ }
70
+ }
60
71
  const results = initRepository(projectRoot, {
61
72
  profile: values["app-friendly"] ? "app-friendly" : "universal",
62
73
  withRoles: values["with-roles"],
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
+ }
@@ -21,6 +21,83 @@ export function buildInitArgs(projectRoot, config) {
21
21
  }
22
22
  return args;
23
23
  }
24
+ function parseVersion(version) {
25
+ const trimmed = version.trim().replace(/^v/, "");
26
+ const match = trimmed.match(/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/);
27
+ if (!match) {
28
+ return null;
29
+ }
30
+ return {
31
+ core: [Number(match[1]), Number(match[2]), Number(match[3])],
32
+ prerelease: match[4] ? match[4].split(".") : [],
33
+ };
34
+ }
35
+ function compareIdentifiers(left, right) {
36
+ const leftNumeric = /^\d+$/.test(left);
37
+ const rightNumeric = /^\d+$/.test(right);
38
+ if (leftNumeric && rightNumeric) {
39
+ return Number(left) - Number(right);
40
+ }
41
+ if (leftNumeric) {
42
+ return -1;
43
+ }
44
+ if (rightNumeric) {
45
+ return 1;
46
+ }
47
+ return left.localeCompare(right);
48
+ }
49
+ export function compareVersions(left, right) {
50
+ const leftParsed = parseVersion(left);
51
+ const rightParsed = parseVersion(right);
52
+ if (!leftParsed || !rightParsed) {
53
+ return left.localeCompare(right);
54
+ }
55
+ for (let index = 0; index < leftParsed.core.length; index += 1) {
56
+ const difference = leftParsed.core[index] - rightParsed.core[index];
57
+ if (difference !== 0) {
58
+ return difference;
59
+ }
60
+ }
61
+ const leftPrerelease = leftParsed.prerelease;
62
+ const rightPrerelease = rightParsed.prerelease;
63
+ if (leftPrerelease.length === 0 && rightPrerelease.length === 0) {
64
+ return 0;
65
+ }
66
+ if (leftPrerelease.length === 0) {
67
+ return 1;
68
+ }
69
+ if (rightPrerelease.length === 0) {
70
+ return -1;
71
+ }
72
+ const length = Math.max(leftPrerelease.length, rightPrerelease.length);
73
+ for (let index = 0; index < length; index += 1) {
74
+ const leftIdentifier = leftPrerelease[index];
75
+ const rightIdentifier = rightPrerelease[index];
76
+ if (leftIdentifier === undefined) {
77
+ return -1;
78
+ }
79
+ if (rightIdentifier === undefined) {
80
+ return 1;
81
+ }
82
+ const difference = compareIdentifiers(leftIdentifier, rightIdentifier);
83
+ if (difference !== 0) {
84
+ return difference;
85
+ }
86
+ }
87
+ return 0;
88
+ }
89
+ function latestWaypointVersion(options) {
90
+ const npmBinary = options.npmBinary ?? process.env.WAYPOINT_NPM_COMMAND ?? npmBinaryForPlatform();
91
+ const latest = spawnSync(npmBinary, ["view", "waypoint-codex", "version"], {
92
+ stdio: "pipe",
93
+ encoding: "utf8",
94
+ });
95
+ if ((latest.status ?? 1) !== 0) {
96
+ return null;
97
+ }
98
+ const version = latest.stdout?.trim();
99
+ return version ? version : null;
100
+ }
24
101
  function hasWaypointConfig(projectRoot) {
25
102
  return existsSync(path.join(projectRoot, ".waypoint/config.toml"));
26
103
  }
@@ -53,3 +130,26 @@ export function upgradeWaypoint(options) {
53
130
  });
54
131
  return doctor.status ?? 1;
55
132
  }
133
+ export function maybeUpgradeWaypointBeforeInit(options) {
134
+ const nodeBinary = options.nodeBinary ?? process.execPath;
135
+ const npmBinary = options.npmBinary ?? process.env.WAYPOINT_NPM_COMMAND ?? npmBinaryForPlatform();
136
+ const stdio = options.stdio ?? "inherit";
137
+ const latestVersion = latestWaypointVersion({ npmBinary });
138
+ if (!latestVersion || compareVersions(latestVersion, options.currentVersion) <= 0) {
139
+ return null;
140
+ }
141
+ console.log(`Waypoint CLI ${options.currentVersion} is older than latest ${latestVersion}. Updating before init...`);
142
+ const update = spawnSync(npmBinary, ["install", "-g", "waypoint-codex@latest"], {
143
+ stdio,
144
+ });
145
+ if ((update.status ?? 1) !== 0) {
146
+ return update.status ?? 1;
147
+ }
148
+ const reexecArgs = options.initArgs.includes("--skip-cli-update")
149
+ ? options.initArgs
150
+ : [...options.initArgs, "--skip-cli-update"];
151
+ const init = spawnSync(nodeBinary, [options.cliEntry, "init", ...reexecArgs], {
152
+ stdio,
153
+ });
154
+ return init.status ?? 1;
155
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "waypoint-codex",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
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