Step 7 av v4.1-execute (Wave 3, Session 4). Legg ny "## Profile (v4.1)"-seksjon i hver kommando-fil rett før "## Hard rules": - trekbrief.md: --profile + VOYAGE_PROFILE + premium default - trekresearch.md: + economy/balanced auto-disable external_research_enabled - trekplan.md: + plan.md frontmatter recording for inheritance - trekexecute.md: + 4-step resolution (flag > env > inheritance > default) - trekreview.md: + opus-default for review-deepening - trekcontinue.md: spesiell — INHERITANCE er default (ikke premium), --profile overstyr emitter stderr-advarsel Tester (13 nye, baseline 432 → 445): - 6 commands × 2 (--profile + VOYAGE_PROFILE) - trekcontinue.md "inheritance"-keyword Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
15 KiB
| name | description | argument-hint | model |
|---|---|---|---|
| trekcontinue | Resume the next session in a multi-session trekplan project. Reads .session-state.local.json and immediately begins the next session. | [<project-dir> | --help] | opus |
Ultracontinue Local v1.0
Zero-friction multi-session resumption. In a fresh Claude Code session, type
/trekcontinue — the command reads the per-project state file
(.claude/projects/<project>/.session-state.local.json), shows a 3-line summary,
and immediately begins executing the next session.
The state file is the contract. Any session-end mechanism may write it
(/trekexecute Phase 8 / Phase 2.55 / Phase 4, the
/trekendsession helper, or — in the future — graceful-handoff).
This command only reads.
Pipeline position:
/trekplan → plan.md
/trekexecute → progress.json + .session-state.local.json
... session boundary, fresh chat ...
/trekcontinue → reads .session-state.local.json, starts next session
See Handover 7 in docs/HANDOVER-CONTRACTS.md for the full schema.
Phase 0 — --help handling
Parse $ARGUMENTS with parseArgs($ARGUMENTS, 'trekcontinue') from
lib/parsers/arg-parser.mjs. Dispatch the usage block ONLY when one of these
two conditions equals exactly true (no substring search, no "contains" check):
flags['--help'] === true, ORpositional[0] === '-h'(single-dash short form — the parser keeps it as positional because the schema does not declare an alias).
In every other case — including when $ARGUMENTS is empty, whitespace-only,
the literal empty string "", or a positional project-dir — fall through to
Phase 1. Do NOT print the usage block on empty args.
/trekcontinue — Resume the next session in a multi-session trekplan project.
Usage:
/trekcontinue # auto-discover state file under cwd
/trekcontinue <project-dir> # explicit project directory
/trekcontinue --cleanup <project-dir> # dry-run: list stale files
/trekcontinue --cleanup --confirm <project-dir> # actually delete (requires status: completed)
/trekcontinue --help # this message
Reads .claude/projects/<project>/.session-state.local.json (per-project,
gitignored). On a valid resumable state, prints a 3-line summary and begins
executing the next session immediately. No interactive confirmation prompt.
State-file schema (v1):
schema_version 1
project string
next_session_brief_path string (validator soft-checks file existence)
next_session_label string
status in_progress | partial | failed | stopped | completed
(completed → no further sessions to resume)
updated_at ISO-8601 timestamp
(unknown top-level keys are tolerated — forward-compat for graceful-handoff v2.2)
Typical flow:
/trekbrief # produces brief.md
/trekplan --project ... # produces plan.md
/trekexecute --project .. # writes session-state on session-end
... (fresh Claude chat) ...
/trekcontinue # reads session-state, runs next session
Phase 0.5 — Cleanup mode dispatch
After parseArgs has resolved $ARGUMENTS, check the parsed flags
object directly (NOT a string contains-check on raw $ARGUMENTS — that
substring pattern was the root cause of Bug 1).
If flags['--cleanup'] === true, switch into the terminal cleanup
flow and do NOT proceed to Phase 1 or any later phase.
Required positional: an explicit <project-dir> (positional[0]).
There is no "clean all" mode — accidental wholesale deletion would be
irreversible. If positional[0] is missing, empty, or starts with -,
print this usage block to stderr and exit non-zero:
Error: /trekcontinue --cleanup requires <project-dir>.
Usage:
/trekcontinue --cleanup <project-dir> # dry-run: list stale files
/trekcontinue --cleanup --confirm <project-dir> # actually delete (status: completed)
Compute mode from parsed flags:
dryRun = (flags['--confirm'] !== true)
confirm = (flags['--confirm'] === true)
Invoke cleanup inline. Emit the concrete project-dir path as a literal token in the Bash command — never a template placeholder — same anti-substitution rule as Phase 2:
node --input-type=module -e "import {cleanupProject} from './lib/util/cleanup.mjs'; const [, dir, mode] = process.argv; const r = cleanupProject(dir, {dryRun: mode !== 'confirm', confirm: mode === 'confirm'}); console.log(JSON.stringify(r, null, 2)); process.exit(r.valid ? 0 : 1)" '<RESOLVED-PROJECT-DIR>' '<MODE>'
Substitute <RESOLVED-PROJECT-DIR> with the literal positional[0]
value you have in your working context, and <MODE> with either the
literal string dryrun or the literal string confirm based on the
booleans above. The validator emits a {valid, errors, warnings, parsed}
JSON record. Print it to stdout. Exit with the validator's exit code.
Cleanup is a terminal mode. It must not fall through to Phase 1/2/3/4.
Operators who want to resume after cleanup must invoke /trekcontinue
again without --cleanup.
Phase 1 — Resolve project directory
The parsed positional[0] from Phase 0 is the explicit project-dir argument,
when present. Otherwise (empty $ARGUMENTS or whitespace-only) auto-discover.
Step 1.a — Reject .md positional argument (SC-2)
If positional[0] is non-empty AND ends in .md, the user almost certainly
pasted a NEXT-SESSION-PROMPT.local.md path instead of a project directory.
Print the following diagnostic to stderr and exit non-zero. Do NOT proceed.
Error: expected <project-dir>, got a markdown file path: <positional[0]>
Did you mean to paste the file path as a project directory?
Usage: /trekcontinue <project-dir>
Step 1.b — Auto-discover candidates
When no explicit project-dir was given, enumerate
.claude/projects/*/.session-state.local.json paths with node -e
(NOT shell glob — harness-mode safety) and emit each as one JSON line of
{"path": ..., "updated_at": ...} so Phase 1 can sort numerically:
!`node -e "const fs=require('fs'),path=require('path');const root='.claude/projects';if(!fs.existsSync(root))process.exit(0);for(const d of fs.readdirSync(root)){const p=path.join(root,d,'.session-state.local.json');if(!fs.existsSync(p))continue;let u='';try{u=(JSON.parse(fs.readFileSync(p,'utf8'))||{}).updated_at||''}catch(_){};process.stdout.write(JSON.stringify({path:p,updated_at:u})+'\\n');}"`
Sort the emitted candidates by Date.parse(updated_at) descending (newest
first) — numeric comparison, NOT lexicographic string compare. The newest
resumable state wins.
Step 1.c — Decision tree
- 0 candidates and no explicit arg: print SC-2 cold-start message and exit:
No active multi-session project here. Start with /trekbrief or /trekplan. - 1 candidate (or explicit non-
.mdarg): continue to Phase 2 with that path. - >1 candidates and no explicit arg: with the Date.parse sort applied, the
newest resumable state wins automatically and the command continues to Phase 2
with that path. (Operators who want a different candidate re-invoke as
/trekcontinue <project-dir>.)
Phase 1.5 — Frontmatter consistency check
Bug 3 contract: producers (/trekexecute, /trekendsession)
write NEXT-SESSION-PROMPT.local.md with YAML frontmatter (produced_by:,
produced_at:). Multiple producers may have written candidates in different
locations; this phase refuses ambiguity before validating the state file.
After resolving the project directory and state-file path, look for two
NEXT-SESSION-PROMPT.local.md candidates:
a. <plugin-root>/NEXT-SESSION-PROMPT.local.md — operator-managed master file
b. <project-dir>/NEXT-SESSION-PROMPT.local.md — producer-written sibling
If both exist:
-
Read both via the Read tool (NOT Bash — same anti-substitution rule as Phase 2).
-
Invoke the consistency validator with both paths emitted as concrete literal tokens (no template substitution at the Bash boundary):
node lib/validators/next-session-prompt-validator.mjs --json --consistency <RESOLVED-PATH-A> <RESOLVED-PATH-B>Replace
<RESOLVED-PATH-A>and<RESOLVED-PATH-B>with the two concrete filesystem paths you have in your working context. The validator emits{valid, errors, warnings}JSON on stdout. -
If
valid: false(typicallyNEXT_SESSION_PROMPT_PRODUCER_MISMATCH): print the structurederrors[](each[code] messageon its own line), list both candidate paths, and exit non-zero. Do NOT proceed to Phase 2. Resolve the conflict by deleting the stale candidate (run/trekcontinue --cleanup --confirm <project-dir>after the current session closes, or remove by hand). -
If
valid: truewith aNEXT_SESSION_PROMPT_WALL_CLOCK_DRIFTwarning (one of the candidates is more than 24h old): print the warning to stderr but continue — long pauses (weekend, vacation) are not failures. -
If
valid: truewith aNEXT_SESSION_PROMPT_STALE_IGNOREDwarning (one candidate is older than the state file'supdated_at): print the warning and continue. The state-anchored check is the primary refusal signal; staleness simply rejects the older candidate.
If only one exists: continue to Phase 2. No comparison needed.
If neither exists: continue to Phase 2. Legacy projects and first-run flows have no NEXT-SESSION-PROMPT files.
Phase 2 — Validate the state file
Phase 1 resolved a concrete state-file path. That path is a real string in your working context — never a template. Phase 2 must read and validate the state file without any placeholder substitution.
Step 2.a — Read the file with the Read tool (no Bash)
Use the Read tool on the resolved state-file path from Phase 1. Do NOT use Bash for the read. The Read tool is deterministic and not subject to shell-substitution errors. Parse the returned JSON body programmatically.
Step 2.b — Schema-validate the parsed object
Verify the schema by invoking the existing validator CLI shim. Emit the
resolved absolute path as a literal string token in the Bash command — the
exact same string you just passed to the Read tool. The validator accepts
--json <path> and prints a {valid, errors, warnings} JSON record:
node lib/validators/session-state-validator.mjs --json <RESOLVED-ABSOLUTE-PATH-FROM-PHASE-1>
Replace <RESOLVED-ABSOLUTE-PATH-FROM-PHASE-1> with the actual path string at
the time you issue the Bash call. There is no template engine; the string is
substituted by you, the model, before the Bash tool sees the command.
Anti-substitution invariant. If you ever find yourself about to emit a literal angle-bracket placeholder, or any other unresolved variable name, to the Bash tool — STOP. The resolved path is a concrete value you already have from Phase 1; emit the value, not a placeholder for it.
Step 2.c — Interpret the result
- Validator exit code != 0 OR
valid: falsein JSON output: print the structurederrors[](each[code] messageon its own line) and exit. Do not proceed to narration. Suggest running the validator directly for follow-up:node lib/validators/session-state-validator.mjs <path>. valid: trueAND any warning hascode: SESSION_STATE_NOT_RESUMABLE(i.e.status: completed): print "no further sessions to resume; project complete" and exit cleanly.valid: trueAND status is one ofin_progress | partial | failed | stopped: proceed to Phase 3.
Phase 3 — Narrate 3-line summary
Print this exact template (using values from the validated parsed object):
Project: {project}
Next session: {next_session_label}
Brief: {next_session_brief_path}
No interactive confirmation prompt — per the brief NFR ("ingen prompts, men la informasjon synes"). The 3-line block is informational only.
Phase 4 — Begin execution
Read the file at next_session_brief_path (it is the brief that the next
session is supposed to execute — typically the same brief.md for
single-brief multi-session plans, or a session-specific spec for parallel
session decomposition). Understand the task and begin executing per the
standard trekplan pipeline. The user did not type a separate "start"
command — /trekcontinue is the start.
If the brief file does not exist (validator emits a warning but does not
fail), print: Warning: next_session_brief_path "{path}" does not exist on disk. Cannot continue automatically. and exit. Do not guess.
Phase 5 — Stats tracking
Append a one-line JSON record to ${CLAUDE_PLUGIN_DATA}/trekcontinue-stats.jsonl
if the env var is set; silently skip otherwise.
{"ts":"<iso-8601>","project":"<project>","next_session_label":"<label>","status":"<status>"}
Profile (v4.1) — inheritance from plan-frontmatter
Accepts --profile <name> where <name> is economy, balanced, premium,
or a custom profile under voyage-profiles/. Default: premium.
Unlike the other voyage commands, /trekcontinue defaults to inheritance
from the resumed plan's frontmatter profile: field rather than to premium.
This keeps a multi-session run consistent across resumptions.
Resolution order (per lib/profiles/resolver.mjs resolveTrekcontinueProfile):
--profileflag (source:flag) — explicit override, emits stderr advisory[voyage] profile inheritance overridden by --profile flag: <plan-profile> → <flag-profile>VOYAGE_PROFILEenv-var (source:env)- Plan-frontmatter
profile:field (source:inheritance) — typical case premiumdefault for v4.0-style plans withoutprofile:(source:default)
The inherited profile drives phase_models.continue for the next session's
orchestration. Operators who explicitly want to switch profiles mid-run pass
--profile <name> and accept the advisory (e.g. drop from premium to
balanced mid-run to save cost on later sessions).
Examples:
/trekcontinue # inherits from plan.md
/trekcontinue --profile balanced # explicit override + advisory
VOYAGE_PROFILE=economy /trekcontinue # env-var override
Stats records emit profile and profile_source per Phase 5 record.
Hard rules
- Idempotent. Running
/trekcontinuetwice in the same Claude session does not advance state — the writer (Phase 8 / hook / helper) advances state only when a session completes. - Zero secrets in the state file. Status, paths, labels — never API keys, never user content beyond filenames.
- NEVER auto-load via SessionStart. The command is operator-invoked only.
Auto-loading would re-introduce the stale-file risk noted in
feedback_next_session_prompt_manual.md. - No interactive prompts. Phases 0–4 must run without
AskUserQuestion. This keeps the command headless-safe.