From claude-code-hermit
Initializes or resumes a work session by loading context from OPERATOR.md and SHELL.md, orienting the agent, and establishing the task to work on.
How this skill is triggered — by the user, by Claude, or both
Slash command
/claude-code-hermit:session-startThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Notify the operator per the channel policy in CLAUDE.md (§ Operator Notification).
Notify the operator per the channel policy in CLAUDE.md (§ Operator Notification).
--task flag (non-interactive autonomous start)If invoked as session-start --task '<text>': use <text> as the task and bypass interactive prompts/questions only. When adopting <text> as this session's task, write it verbatim as the ## Task first line — no elaboration, reordering, summarization, or truncation — so the collision guard's exact same-task comparison stays valid on a routine's re-entrant call. Operator notifications in step 8 still follow the channel policy above. Skip the NEXT-TASK.md presentation (step 6), the "What should I work on next?" / "What should I help with?" prompts (steps 9b/10), the resume prompt (step 9's "continue the current task or start a new one" ask — the collision guard already made the resume/defer decision non-interactively), the Tags prompt (step 11), the step-12 first-step confirmation, and the "After confirming the plan with the operator" plan-confirmation prose in the task-source paths. Do not ask for plan confirmation. Steps 1–3 run unchanged; the collision guard runs next. On a live-state collision (the On collision — live branch below) it aborts before step 4 — no session is created, renumbered, or otherwise mutated. On a recovery-state collision (the On collision — recovery branch below) it archives the crashed session and proceeds to step 4 as a new session.
Collision guard (runs immediately after the step-3 runtime.json read, evaluated against the SHELL.md content already available from the startup injection; before step 4 routing and before any session is created, renumbered, or its ## Task overwritten). This is the --task path's non-interactive resolution of step 9's resume check, which this path otherwise bypasses along with the other interactive prompts.
runtime.json session_state is in_progress or waiting, AND SHELL.md's current ## Task is non-placeholder, AND it collides with <text>. The waiting_reason selects the on-collision action below: operator_input/conservative_pickup/null are live states with a genuine pending task (per channel-responder/SKILL.md); unclean_shutdown/dead_process (and their _no_channel variants) are crash-recovery prompts whose ## Task is a stale pre-crash task still awaiting the operator's archive-or-resume decision, not work actively in progress.## Task in SHELL.md, trimmed, and compare it to <text>, also trimmed. The placeholder <!-- Awaiting next task --> counts as empty (not a collision). Equal (post-trim) → not a collision, this is the same task continuing (e.g. a routine's own re-entrant call re-seeding the identical <text>; the --task contract above stores it verbatim, so the strings match) — proceed unchanged. Different → collision.waiting_reason (unclean_shutdown/dead_process/*_no_channel): the crashed session's ## Task is not live work, so do not subordinate the fresh task to it. Treat <text> as answering the pending recovery prompt with "archive as partial, start fresh": pipe Status: partial\nBlockers: none\nClosed Via: operator\n on stdin to bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts archive --mode=close --state-dir=.claude-code-hermit; if the returned ok is false, surface the reason and abort rather than proceeding with a fresh session on top of an unarchived crash. On ok === true, clear waiting_reason and last_error in runtime.json, then proceed below with <text> as a new session (do not defer to NEXT-TASK.md). Append one SHELL.md ## Progress Log line and notify per channel policy: [HH:MM] session-start --task archived crashed session (partial), starting fresh: "<incoming task, one line>".waiting_reason or in_progress (operator_input/conservative_pickup/null, or in_progress):
## Task. Do not create or renumber a session.<text> to .claude-code-hermit/sessions/NEXT-TASK.md, using the same markdown shape proposal-act's "Create a session task" step writes (# Next Task / ## Task / ## Context / ## Suggested Plan). If NEXT-TASK.md already exists (another task is already pending), do not overwrite it — this incoming task is dropped, not queued.## Findings and ## Progress Log: [HH:MM] session-start --task deferred "<incoming task, one line>": session <session_state> with "<current task, one line>". If NEXT-TASK.md already existed (step 2's drop case), say "dropped (NEXT-TASK already pending)" instead of "deferred".idle, or ## Task is placeholder/empty, or same task) → proceed as normal below.When starting a new session:
All state lives under .claude-code-hermit/ in the project root.
Read .claude-code-hermit/config.json for agent identity settings (agent_name, language)
If the SessionStart hook output above includes "---Upgrade Available---": if the banner says REQUIRED: (always-on hermits), treat running /claude-code-hermit:hermit-evolve unattended as the hard first action of this session — do it before other work, then continue. Otherwise (advisory wording) just mention it to the operator and do NOT block session start.
Read state/runtime.json for lifecycle state (fresh read — re-read the file(s) now; do not reuse a value cached in context from before compaction). This is the single source of truth — never parse SHELL.md Status: for decisions.
context_cleared === true in runtime.json, set a local suppress_startup_ping flag to true; otherwise set it to false. Then unconditionally write context_cleared: false back to runtime.json regardless of which recovery path follows — this consumes the marker so a later genuine boot doesn't inherit it. This must happen before the recovery sub-branches below because those branches can stop the flow early.state/compact-requested.json if present (rm -f, ignore if absent). This marker is arc-scoped (written by session/proposal-act at a work-done boundary so the watchdog's routine-hygiene compactor can waive its interval cooldown once); it must never survive into a new session and influence that session's own compaction timing.state/.lifecycle.lock non-blocking. If held by another process (hermit-start.ts, hermit-stop.ts), tell the operator "A lifecycle operation is in progress — wait for it to complete" and abort.transition is not null, run bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts recover --state-dir=.claude-code-hermit. It owns the full deterministic branch table (archiving+target-missing → re-archive with a degraded payload; archiving+target-exists → skip straight to SHELL.md cleanup; cleaning → re-run SHELL.md cleanup; picks idle-vs-close cleanup semantics via the transition_mode field it reads, falling back to a full close for markers left by a pre-upgrade crash). Parse the returned JSON: if ok === true, notify the operator: "Recovered from interrupted transition. Session is now idle." If ok === false, treat this as the unclean-shutdown case below instead — the interrupted state could not be resolved mechanically.last_error == "unclean_shutdown":
session_state to waiting and waiting_reason to "unclean_shutdown" in runtime.json. If watchdog_restart_reason is set in runtime.json, include it in the channel message: "Came back up — watchdog restarted the session (reason: [watchdog_restart_reason]). Previous task: [task from SHELL.md, or 'unknown']. Reply with (1) to archive as partial and start fresh, or (2) to resume where we left off." Otherwise use: "Came back up after unclean shutdown. Previous task: [task from SHELL.md, or 'unknown']. Reply with (1) to archive as partial and start fresh, or (2) to resume where we left off." Then stop — channel-responder handles the reply. If heartbeat.waiting_timeout is set, heartbeat will auto-transition to idle after timeout elapses with no channel activity.push_notifications === true, the recovery prompt cannot be answered. The Operator Notification protocol will still fire PushNotification with the message, but immediately set waiting_reason to "unclean_shutdown_no_channel" and rely on heartbeat.waiting_timeout to auto-transition the session to idle (heartbeat step 6 flips session_state to idle without touching SHELL.md; the recovery prompt's archive-vs-resume choice is not made automatically — operators who want explicit archive-on-timeout semantics should configure a channel). If waiting_timeout is unset, log a Findings entry recommending the operator add one or configure a channel for two-way replies.partial and start fresh, (b) Resume as-is.last_error and watchdog_restart_reason after the operator decides (so a later unrelated unclean shutdown does not re-announce a stale watchdog restart).session_state == "dead_process": same flow as unclean shutdown above (including the push-only setup guard). Set waiting_reason to "dead_process" (or "dead_process_no_channel" in the push-only case) in runtime.json. Message: "Process died unexpectedly. Previous task: [task from SHELL.md, or 'unknown']. Reply with (1) to archive as partial and start fresh, or (2) to resume where we left off."session_state is idle → ready for new task. If in_progress or waiting → existing session, offer resume.
3b. Watch registry reset. Read state/monitors.runtime.json and clear all entries unconditionally — watches are session-scoped, so any previous entries are stale. If the file is missing, skip. This runs on every session start (new, resume, or crash recovery) before any watch registration occurs.Session state routing — evaluate the fast-path gate before running session-archive.ts.
Fast path (skip session-archive.ts) — ALL five must be true:
runtime.json was found and parsed successfully (not missing, not malformed)session_state ∈ {in_progress, idle, waiting}transition is nulllast_error is null.claude-code-hermit/sessions/SHELL.md existsIf all five are true: SHELL.md content is already available from the startup hook injection. Proceed directly to step 4b with the data already in hand. Do not run session-archive.ts here. Read session_id from runtime.json — if set and SHELL.md **ID:** still contains the placeholder S-NNN, update it to the actual session ID (e.g., S-009) in-context, no script call needed. Similarly, if **Started:** still contains the placeholder YYYY-MM-DD HH:MM, replace it with created_at from runtime.json (or the current date/time if created_at is absent), in-context, no script call needed.
Slow path (run session-archive.ts open) — any condition above fails:
runtime.json is missing or malformed → first run or corrupted statesession_state is dead_process or any unrecognized valuetransition is not null → already handled by the P3 recovery check in step 3 above; if it's still non-null here, recover didn't fully resolve it — re-run recover once more before falling through to openlast_error is not null → error recovery neededSHELL.md is missing → open must create it from templateOn the slow path: run bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts open --state-dir=.claude-code-hermit (empty Task: payload if no task is known yet) to create/update SHELL.md and pre-compute the session ID. Gate on the returned ok; if false, surface the reason to the operator before proceeding.
4b. If runtime.json session_state is idle (session between tasks — SHELL.md exists but no active task):
Task: <text> on stdin to bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts open --state-dir=.claude-code-hermit to update runtime.json session_state to in_progress and fill in Task. After confirming the plan with the operator, create native Tasks (TaskCreate) for each step.archive --mode=idle)Read .claude-code-hermit/OPERATOR.md for project context and constraints
5b. Baseline audit offer (first session only).
Check for .claude-code-hermit/.baseline-pending. If absent, skip this step entirely.
If present:
Notify per channel policy (always-on: channel; interactive: inline). Operator message:
"First session on this project. Want me to run a one-time audit using the plugins you installed at hatch? It'll surface CLAUDE.md gaps and automation opportunities. (yes / no)"
In always-on mode, only this single prompt and the final summary go through the channel. Plugin invocations run in-agent without channel chatter.
Handle response:
.claude-code-hermit/.baseline-pending immediately (before invoking any skill). Marker semantic = "we haven't offered yet." Once consented, the offer is consumed regardless of invocation outcome. If a skill crashes mid-run, the operator re-invokes it manually; we do not re-offer on next session. Then proceed to step 3.Pre-flight: scan config.json scheduled_checks for any entry in the fixed list below with enabled: true. If none qualify, delete the marker silently and continue to step 6.
For each skill in the fixed list below, in order:
/claude-md-management:claude-md-improver/claude-code-setup:claude-automation-recommenderDo NOT invoke /claude-md-management:revise-claude-md — it is a session-trigger skill, not an audit, and runs separately via its own scheduled_checks entry.
For each audit skill:
config.json scheduled_checks for a matching skill field with enabled: true. If absent or disabled, skip silently./claude-code-hermit:proposal-create as one proposal per plugin invocation, passing Evidence Source: operator-request and with source: operator-request in the frontmatter. (Not auto-detected — that routes through reflection-judge expecting cross-session evidence citations the audit cannot provide.) Write the Problem section as a prioritized summary of all findings (top 3 inline, remainder as a bulleted list).Surface a single-line summary to the operator (channel in always-on, inline otherwise):
"Baseline audit done — {N} proposals queued for your review. Reply and I'll walk you through them."
(Channel voice: no PROP-ids, no slash command — the channel operator can't run one. Inline/terminal output is exempt, but this single line stays plain for both.)
Guard: the marker is the one-shot gate. Absent marker → this step never fires.
Note for maintainers: md-audit and automation-recommender are already scheduled on 7-day intervals via scheduled_checks. This step pulls the first run forward to day 1 with operator consent — it is not an independent execution path.
Check if .claude-code-hermit/sessions/NEXT-TASK.md exists. If it does:
config.always_on is true AND escalation is balanced or autonomous): there is no operator to present to — auto-accept the prepared task. Use its ## Task line as this session's task (as if the operator had accepted it), then delete NEXT-TASK.md. This is the deterministic path the session Work-done flow (§8) and heartbeat Idle Agency invoke with a bare session-start.config.always_on is true AND escalation is conservative): do not auto-start. Leave NEXT-TASK.md in place — the heartbeat conservative branch owns pickup (notify + set waiting). Continue without adopting a task from it.config.always_on is false): present the prepared task to the operator as the suggested task for this session.
NEXT-TASK.md and proceed with their task.NEXT-TASK.md in place for a later session.NEXT-TASK.md only once its task has actually been adopted as this session's task (auto-accepted, accepted, or replaced by the operator's own task). Never delete a queued task that was not started.Scan .claude-code-hermit/proposals/ for files with Source: auto-detected and Status: proposed. If any exist, mention: "There are N unreviewed auto-detected proposal(s). Review with /proposal-list when ready." Do NOT block the session — this is a one-line notification only.
7b. Interactive morning brief. If config.always_on is false AND config.routines contains an enabled entry with skill containing brief --morning: run the morning brief inline — generate a brief emphasizing where things stand, pending proposals, and what's on deck. No dedup needed — interactive sessions are short-lived.
If agent_name is set, use it in the greeting (e.g., "Atlas reporting in." or "{name} a reportar." if language is pt). If language is set, communicate with the operator in that language for the rest of the session.
In always-on mode: if no recovery message was sent in step 3, notify the operator via channel with a startup ping (1 line): "[name or 'Hermit'] online. Reviewing session state." Skip this ping if a recovery question was already sent — the recovery message is the boot signal. Also skip if suppress_startup_ping is true (set in step 3) — this invocation follows a watchdog context-clear, not a genuine restart.
If resuming an existing session (runtime.json session_state is in_progress or waiting):
TaskList to see current plan steps. Present the current task, progress (completed/remaining tasks), and blockers.blocked: suggest running /debug to diagnose tool/hook failures before re-attempting the blocked worksession_state is idle):Task: <text> on stdin to bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts open --state-dir=.claude-code-hermit to fill Task and update runtime.json session_state to in_progress. After confirming the plan, create native Tasks for each step.If starting a new session:
Task: <text> on stdin to bun ${CLAUDE_PLUGIN_ROOT}/scripts/session-archive.ts open --state-dir=.claude-code-hermit to create the session with the task. After confirming the plan, create native Tasks (TaskCreate) for each step.Tags: field in SHELL.md. If skipped, leave blank.
11b. Watch registration. If config.monitors exists and has enabled entries, invoke
/claude-code-hermit:watch start to register them. (Registry was already cleared in
step 3b.) This is silent — do not prompt the operator about watch registration..claude-code-hermit/OPERATOR.md (always).claude-code-hermit/sessions/SHELL.md (if exists) (re-read before writing to it or before reusing a value cached in context from before compaction; after a compact-source start the injected capsule's task/progress lines suffice for orientation — don't re-read just to reconstruct context).claude-code-hermit/sessions/S-*-REPORT.md (for continuity — only the latest one; skip after a compact-source start, the capsule carries its path).claude-code-hermit/state/runtime.json (always — for lifecycle state)Do NOT load all session reports — only the most recent one.
npx claudepluginhub p/gtapps-claude-code-hermit-plugins-claude-code-hermitStart or resume a work session with full context loading and work tracking. Use at the beginning of work.
Bootstraps Claude Code sessions by organizing files, generating CLAUDE.md, managing soul purpose lifecycle with completion protocol and context harvesting. Use /start or /init.
Loads session handoff, reviews lessons, and runs environment health checks on session start. Triggered by '/session-start' or continuation phrases like '이어서 해줘'.