session-autonomous - work approved GO items unattended
A credo session runs in exactly one mode - active, passive, or autonomous - set by
the /credo:session-* commands and surfaced on every prompt by the session-mode inject
line. This skill is the umbrella for autonomous mode: the user is away, you work
approved GO items on your own, keep the session alive, respect the budget caps, notify via
ntfy, and hibernate cleanly at the end. It is the dach / umbrella over the credo building
blocks - it wires them together and adds the unattended-run machinery, and it duplicates
none of their content.
Autonomous mode is only in force while the autonomy flag credo-autonomy-active is set -
which is what the /credo:session-autonomous command sets (and it lifts the
credo-autonomy-paused opt-out). If that flag is not set, do not run the keep-alive or
hibernate behavior below.
Bootstrap - enter the mode only on an unambiguous grant
This skill may LOAD on a full-autonomy / AFK-handoff intent, but entering autonomous mode
requires an unambiguous, explicit user grant. If this skill loaded because the user just handed
off full-autonomy / unattended / AFK work and the mode is NOT yet set (no credo-autonomy-active
flag), FIRST enter autonomous mode by running /credo:session-autonomous. That command runs
session-mode-set.sh autonomous, sets the flag, and activates the rules below - which resolves the
chicken-and-egg problem of needing the mode set before this skill's keep-alive can apply. Then
follow the rules below. If the mode is already autonomous, skip this and continue.
Do NOT enter autonomous mode on a vague or casual signal (for example a bare "keep going", "carry on", "work on this"); only on an unambiguous full-autonomy / AFK grant such as "run this unattended", "go fully autonomous", or a clear AFK handoff. If unsure whether the user really wants unattended autonomy, stay in normal (non-autonomous) collaboration and confirm with the user first rather than setting the flag. A user who never asks for autonomy is never put into autonomous mode.
Capture and persist a suspend-on-idle directive on entry. If the grant (the
/credo:session-autonomous argument or the user's natural-language handoff) includes an
explicit suspend-on-idle order ("suspend when done", "power down at the end", "hibernate
afterwards", German "am Ende suspend", "danach runterfahren"), record it durably right now:
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-directive.sh" set
An explicit revocation ("no suspend", "leave it on", German "kein suspend", "lass an") clears
it (... clear). A directive already set in THIS session stays in force across a re-invoke of
/credo:session-autonomous and across context compaction - do NOT drop it just because the
latest invocation carried no argument (that persistence is the whole point; it fixes the bug
where a standing order was silently forgotten on re-invoke). The directive is per-session,
stored on disk keyed by session_id, and re-injected on every prompt by the session-mode inject
hook, so it survives compaction. It changes only the end-of-run power-down gate (see "Suspend
directive: persistence, presence, and the attended/unattended split" below). Never set it from
mere user presence or a casual remark - only an explicit order.
Common core (shared - read the session-active skill)
Autonomous mode uses the same canonical common core as every credo session skill. It
is defined once in the credo session-active skill and applies here in full - read it
there. It covers: CLARIFY-FIRST and the go-gate; clarify via Ask (G1); bug report is not
an immediate fix (G2); read-back scaled to complexity (A4); the soft old-item reminder; no
silent rename / restructure plus consistency sweep (G6) and independent evaluation of
foreign handoffs (G7); the authority order (E5); the ntfy hybrid model (D); the git-push
policy (G5); the safety skill always; and the building blocks a session ties together.
The autonomous specifics below narrow or extend that core - they do not replace it.
Where the core points at a building block, that still holds here. In particular, ALL
budget cap / reset / 09:00-guard / task-sizing / weekly-99 / commit-identity rules live in
the credo budget skill; this skill references it and never restates a cap value.
Output convention - item references in inline code
Item references are always written in inline-code style: #37, #90, #91 (backticks) -
never bold or plain. This improves scannability of item numbers.
Autonomous-mode specifics (A3)
Steward, not initiator
In autonomous mode you are a steward of already-approved work, not an initiator. Work ONLY
items in 1_todo/2_go - approved, buildable GO items (credo items go-gate). Do NOT start
new features, invent scope, or make product decisions on the user's behalf. Anything not
already GO waits (or becomes a deferred question, below); it does not get built
autonomously.
go=go: a 2_go item IS buildable by the folder - build it (best effort), never self-skip or
self-demote it for size, UI, or "not sure it is verifiable". See the go=go build-side anchor
in the credo items skill for the full rule and the hypothesis-vs-open-decision line. A
stale-looking, open-looking body is not "not buildable" either: before treating a 2_go
item as still-open, read the WHOLE body plus the requirements log and audit reports (the
read/build-gate in the credo items skill).
Work the WHOLE queue, not just one thread. After you finish an item, immediately pick the next
buildable 2_go item and continue - keep going until the buildable queue is empty (confirmed by
the fresh listing in "Empty buildable queue = end-of-run" below). Building every buildable GO
item IS the mandate of autonomous mode, not over-reach. "I built the thread I started with" is
NOT a reason to stop while other buildable items remain.
Autonomous / AFK runs are read-heavy, so isolated writing pre-work has room here: for a clarify
item blocked by a missing measurement, mockup, or feasibility proof, use the sandbox skill
(.credo/sandbox-tmp/, no production code, no commit) rather than making a product decision.
A non-buildable item in 2_go
An item is normally clarified when it is in 2_go (GO=GO). First rule out mere staleness: a
head or note that merely reads "open / not built" is NOT a non-build reason - read the whole
body plus the requirements log and audit reports before judging (read/build-gate, credo
items skill), because the clarification or build is often already there. Only if the item
is genuinely non-buildable, act by the reason:
- Genuine user-only decision (the Named-Decision-Test in the credo
itemsskill passes - typically surfacing mid-build): do NOT guess and do NOT build on an invented decision. Raise a deferred question (below) AND move the item2_go -> 1_clarifymarked URGENT - the sanctioned carve-out (credoitems). It probably leaves something broken, so it is top of the clarify queue for when the user returns. - Hard block on another unbuilt item: this is the
3_blockedpath (credoitems), not a self-demote. - Anything else (placement / hygiene, "too big / too hard"): do NOT self-demote -
placement is a move-side axis owned by the entry gate (credo
migrate). FLAG it (in the digest and the handoff) rather than silently skipping it.
Auto-unblock (credo items) still applies during the run: when an item reaches 2_done,
check its blocks and return any now-unblocked 3_blocked item to 2_go.
Bringing up a local surface to verify (autonomous)
A ui: true item is not verify-dead in autonomous mode. If its runtime surface is down, and
you can POSITIVELY verify the target is local (a process on THIS machine, bound to localhost -
not a deployed, remote, or shared environment), bring it up or restart it per the
project-declared procedure and then run the credo verify skill. Locality is judged by where
the process runs, NOT by the git branch: a checkout named main / develop / prod does not
make it remote. If locality cannot be positively established, do NOT restart - defer the
visual verify as human-only. See the credo verify skill for the full rule and the config key.
Never interrupt an autonomous run for a mode change (hard rule)
In autonomous mode the agent NEVER asks via the Ask tool about switching mode - not even
if the user keeps prompting during the autonomous run. An autonomous run must not be
interrupted for a mode-awareness question. At most, the agent may mention in normal output
that a mode change has to be made manually (via a /credo:session-* command) or on an
explicit user request; it never raises an Ask round to propose one. A mode switch happens
only on an explicit user instruction. This is the exception to the common core's
"Suggest a session mode when none is set" rule: that Ask-based suggestion logic applies
only in presence or no-mode sessions, never in autonomous.
Never build a skill autonomously (hard guarantee)
The credo skill-capture skill is mode-gated, and autonomous mode takes its strictest
branch: autonomous mode NEVER builds a skill from a recurring workflow, no matter how often
the pattern recurs. Building a skill needs an explicit user GO, which an autonomous run does
not have; a build-on-detection rule would be a showstopper. When you notice the same
multi-step workflow recur (about three times), append ONE candidate note to
.credo/skill-candidates.md and continue the actual work - do not stop, do not ask, do not
create the skill. A later presence-mode session picks the candidate up. This is consistent
with steward-not-initiator: noticing a pattern is fine, acting on it into new tooling is not.
Budget caps are always on
Guardrail-availability gate (autonomy never runs without budgets/limits). At autonomous-mode
entry, and before any autonomous start, check budget-data availability via the read-only
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-budget-read.sh":
- Exit 0 (fresh data): percentage caps are measurable and MANDATORY - proceed as today.
- Exit 3 or 4 (no cache / stale cache): percentage caps CANNOT be enforced (credo
budgetskill, B8 - the fail-safe caps are percentages too, so they are equally unenforceable). Do NOT run blind and do NOT silently ignore budgets. Use AskUserQuestion with three options: a. Install thelimitplugin for real budget safety, then re-check availability. b. Run with a wall-clock timebox (max X hours / until a clock time) - the only guardrail enforceable without the cache. Record the deadline and self-enforce it: end the run viacredo-autonomy-off.shwhen the clock reaches it. c. Proceed without budget guardrails - an explicit, user-accepted risk.
This gate is what makes "autonomy never runs without budgets/limits" true. Send the come-to-PC ntfy before the AskUserQuestion (per the ntfy hybrid).
Budget enforcement is unconditional in autonomous mode. Apply the credo budget skill in
full: the daily cap schedule, the critical 09:00 guard, the 5-hour guard (skill behavior,
check frequently including while subagents run, stop subagents with TaskStop before the
ceiling), the task-sizing recommendation, the absolute fail-safe caps, and the
commit-identity gate before every commit. Before starting an autonomous run, the main agent
first confirms with the user whether the default caps fit or need a temporary override, and
until when (per the budget skill), and performs the mandatory budget-start read-back (see
"Budget-start read-back" below) - show the schedule row in force and reflect the
understanding back before starting (full read-back on the first start, at least the short
form on every start). Never exceed a cap to finish "just one more thing".
Keep-alive (hook-enforced, only while credo-autonomy-active is set)
Keep the session awake so an unattended run does not fall asleep while there is open work
and budget. "Open work" means BUILDABLE work - at least one buildable item remaining - NOT
"any file physically in 2_go" (see "Empty buildable queue = end-of-run" below). When no
buildable item is left, that is an end-of-run condition, not a reason to keep the keep-alive
spinning. This discipline is now hook-enforced. A registered Stop hook
(credo-autonomy-keepalive.sh, wired in hooks/hooks.json) fires when you try to end the
turn: if autonomy is active and no self-wake is marked, it blocks the stop and instructs you
to call ScheduleWakeup now (and mark it). Paired with the registered UserPromptSubmit hook
(credo-autonomy-clear.sh), any real user message turns autonomy off. The enforcement is a
nudge, not a guarantee of infinite wakefulness: the hook forces the block plus instruction,
but actually staying awake still relies on you then calling ScheduleWakeup. It is loop-safe -
the hook forces AT MOST ONE continuation per stop attempt (via the stop_hook_active guard)
and lets the stop through once a future wake is marked, so it can NOT spin forever. Outside
autonomous mode (no flag set) the hook is completely inert - a plain no-op stop.
- ScheduleWakeup is the PRIMARY self-wake mechanism. Its single delay is clamped to [60, 3600] seconds, so for a longer pause CHAIN several wake-ups rather than one long one.
- Record each planned wake with
credo-autonomy-wake-mark.sh(same delaySeconds as the ScheduleWakeup call). This is what the Stop hook checks to let the turn stop, so marking the wake is what satisfies the enforcement. - On each wake, re-check the flag. If autonomy has been turned off (the user returned, or the run ended), do not keep building - end quietly.
- Never end a turn without a scheduled wake-up while the flag is set and there is open work plus budget. The Stop hook enforces this nudge, but uphold the duty yourself rather than relying on the block.
- When the run is truly finished, on a showstopper, or at the weekly hard limit, end the mode
deliberately with
credo-autonomy-off.sh- it clears the flag and sets the paused opt-out so the Stop hook stays inert and you may stop. EXCEPTION: if a suspend-on-idle directive is set, that same deliberate exit MUST first run the power-down sequence (see "Empty buildable queue = end-of-run"); a barecredo-autonomy-off.shrefuses (exit 1) while the directive stands, and the clean exit iscredo-autonomy-off.sh --after-suspendas the final step of the power-down (or--overrideon an explicit user "leave it on"). announced = committed: no deliberate end-of-run - clean-done, showstopper, or weekly hard limit - ends a directive session without the power-down or an explicit override.
Wake-up offsets after a limit reset (default 5 minutes, fallback 1) come from the budget
skill's wakeup.* config - use them when you pause for a limit to reset.
5h-budget-guard (autonomous only, hook-enforced)
Autonomous runs pace the 5h axis on a staggered ladder that the credo-5h-budget-guard.sh
PreToolUse hook enforces (it fires in the main agent AND inside subagents). This applies
ONLY in autonomous mode; active and passive are unchanged. The ladder OVERRIDES the budget
skill's soft/hard band on the 5h axis (no double-firing); everything else in the budget
skill still holds. Full rationale: docs/TODO-credo-5h-budget-guard-concept.md.
Two tracks (the main agent orchestrates - spawns, commits, schedules; a subagent runs ONE task and reports back):
- Main track: 83 soft, 87 soft, 90 soft-strong, 92 HARD, 97 Lockdown.
- Subagent track: 83 soft, 90 HARD, 92 HARD.
Zones:
- Soft zone = recommendation only. The hook injects a throttled, concrete instruction (wind down, no big new fan-outs, wrap up running subagents, secure results); the agent stays at the wheel and judges. It does NOT block. Do not capitulate early - the hard zone is the safety net, so exploit the budget deliberately up to it.
- Hard zone = the hook BLOCKS disallowed tool-calls. Still allowed in the hard zone:
gitcommit / push, writing under.credo/,TaskStop,ScheduleWakeup, andcredo-autonomy-wake-mark.sh. New agent spawns and builds are blocked. At 92 the main agent hard-kills running subagents viaTaskStop, then does only organisational work (commit / push, write the resume block, task status). At 97 (Lockdown) everything is dropped - even an open commit / push - and only the resume wake-up is set.
resume-after-reset.md protocol
Location .credo/process/resume-after-reset.md (durable, git-excluded like the other
.credo process files). It is a ROLLING log of at most TWO blocks: the newest block always
on top, the previous one below it, and the oldest drops out entirely when a new one is
added. Each block records:
- the write timestamp (date + time + TZ),
- the exact 5h-reset time this block is waiting for,
- the open remaining work + next steps (folded in from the subagents' PAUSE reports and the main agent's own state).
After the wake-up the main agent works EXCLUSIVELY the newest block (the one written just before the reset that just happened), never the older one below it; it marks done points as done. If it runs into the limit again it writes a new block on top and the oldest drops out.
Exception - 97 % Lockdown: write NO protocol (it costs tokens that are already scarce at 97 %). Instead set the resume wake-up IMMEDIATELY and stop; after the reset, continue from the session context.
Auto-resume - only the credo method
Pausing across a 5h reset and coming back uses ONLY the credo-documented keep-alive / wake
method described in the Keep-alive section above: ScheduleWakeup as the primary self-wake,
marked with credo-autonomy-wake-mark.sh (same delaySeconds) so the Stop hook lets the
turn stop, and the offset AFTER a reset taken from the budget skill's wakeup.* config
(default 5 minutes, fallback 1). Do not invent any other wake mechanism.
compact-plus precedence (5h reset wins)
The 5h-reset wake-up takes PRECEDENCE over compact-plus. On a collision - the 5h axis is near its cap AND the session-context threshold has been reached - do NOT run compact-plus before the reset (it costs tokens and could blow the 5h limit). Set the reset wake-up, stop, and run compact-plus only AFTER the reset, once it is safe. The same applies to the weekly axis.
Per-task and per-question ntfy
Autonomous mode is where the common-core ntfy hybrid does the most work. Send every ntfy
push through the helper ${CLAUDE_PLUGIN_ROOT}/scripts/credo-ntfy-send.sh "message" (with
-t "Title" and CREDO_NTFY_PRIORITY=high as needed); it resolves the topic/server through
the cascade internally (credo-config.sh get personal.ntfy_topic / personal.ntfy_server)
and is a silent no-op when ntfy is not configured, so you never touch the topic directly.
Send an immediate high ntfy for come-to-PC events (a deferred question, a blocker /
showstopper, a budget cap reached, run completion, the pre-hibernate veto) and BEFORE the
blocking action.
Progress is bundled into one digest per ntfy.digest_interval_minutes, and - when ntfy is
configured (a personal.ntfy_topic is set) - sending that digest is MANDATORY per interval
whenever there is progress; it is NOT the agent's discretion to judge it "not important
enough" and stay silent (this is what fixes digests arriving far too rarely). With no topic
set, ntfy stays silently skipped (see the end of this paragraph). Every completed item in the digest carries the full content
standard from the common core (what / how / where / why); a terse one-liner is not
acceptable. Prefer one message; if it exceeds ntfy's size limit, split into n/m messages.
If personal.ntfy_topic is empty, skip ntfy silently - but then note that autonomy is
running blind on notifications. Run completion is high.
Deferred-question flow (core of autonomous mode)
When you hit a previously-unknown question that genuinely needs the user - one you cannot
self-resolve up to authority level 3 - do NOT stop the whole run and do NOT guess. First
confirm it is genuinely still open: read the WHOLE item body plus the requirements log and
existing audit reports before raising it (read/build-gate, credo items skill) - a question
that merely looks open in a stale head is often already clarified there, and must not be
re-raised. Only if it is truly unanswered:
Send an immediate ntfy
highstating the question clearly (come to the PC).Schedule a wake-up for the deferred-question window -
windows.deferred_question_minutes(default 5) - to check for an answer:"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get windows.deferred_question_minutesIf the answer arrives within the window: incorporate it and continue. Log it verbatim (credo
requirements-verbatim).If no answer arrives: adopt a documented default - record the decision and its rationale in the item / handoff so it is auditable - and continue fully autonomously. Do not block the run on an absent user.
This replaces blocking on the user with a bounded wait plus a safe, documented fallback. If
a subagent is the one that hit the question, use return-and-resume (credo orchestration):
the subagent returns {status: needs_decision, question}, the main agent obtains the answer
(user, verbatim log, or documented default) and passes it back via SendMessage so the
subagent continues with full context.
Empty buildable queue = end-of-run (kills the idle loop)
No buildable item remaining is an END-OF-RUN condition. The keep-alive notion of "open work"
means BUILDABLE work, not "any file physically in 2_go". This closes the limbo where an
agent keeps the keep-alive alive while refusing to build (the RETRO's ~7h idle loop). A file
in 2_go that the agent is treating as non-buildable does NOT count as open work - flag it
(the section above) and, if it is the only thing left, the buildable queue is empty.
"Buildable" = can be advanced RIGHT NOW. An item is buildable only if it can, at this
moment, actually be built further and moved toward 2_done. A 2_go item whose remaining
work hangs ONLY on an unbuilt dependency, or ONLY on a still-open user decision, is NOT
buildable - it counts as empty for this gate, exactly like an empty folder. Do NOT read such
leftovers as "GO is not empty, therefore not finished, therefore no suspend". "GO is not
empty", a self-declared showstopper (a context showstopper included), and "I was not finished
yet" are NONE of them a reason to bypass a standing suspend-on-idle directive when nothing is
factually buildable any more. If the only thing keeping you awake is blocked or
decision-gated remnants, the buildable queue is empty and end-of-run is reached.
Fresh-listing backstop (mandatory before declaring done or powering down). Before an autonomous run declares itself "finished" OR starts the power-down / suspend sequence, it MUST FRESHLY list the GO folder right then - do not trust an earlier snapshot:
ls -1 .credo/items/1_todo/2_go/
Judge the actual current contents:
- If buildable, open, autonomous-eligible items are there, the run may NOT stop without a reason. Either build them, or - for every remaining item - name the concrete non-build reason explicitly (a user-only decision, a hard block, or a placement / hygiene flag; see "A non-buildable item in 2_go" above). "I thought I was done" is not a reason.
- Only once the listing is FACTUALLY empty, or every remaining item is flagged non-buildable WITH its reason, is the buildable queue empty and the end-of-run / power-down sequence allowed to proceed.
When the buildable queue is empty (confirmed by the fresh listing above), run this
end-of-run sequence. The ORDER matters: whether a suspend directive is set decides whether
credo-autonomy-off.sh may flip the flag on its own or must ride the power-down first.
No suspend directive set (and sleep.enabled false):
- Send an immediate
default-priority ntfy stating nothing was buildable -default, nothigh, because it need not wake the user. - End autonomous mode via
credo-autonomy-off.sh(clears the flag, makes the Stop hook inert so the run can stop). The machine stays on.
A suspend directive IS set (or sleep.enabled true) AND sleep.command present: a bare
credo-autonomy-off.sh will REFUSE (exit 1) while the directive stands - the flag flip is the
LAST step, not the first. Run the power-down sequence:
- Send an end-of-run ntfy (
defaultfor nothing-buildable,highfor all-work-completed). - Schedule a ~20 min wake (
windows.veto_minutes) as a veto window. - No veto within the window -> power down, gated by the combined end-of-run gate below:
autonomous AND buildable-queue-empty AND (a suspend directive is set OR
sleep.enabledis true) ANDsleep.commandis present. A set directive OVERRIDESsleep.enabled: false. This REUSES the existing power-down procedure below (veto window, retry plus success detection, secure-work-first, the exactsleep.command) - do not duplicate it. - As the FINAL step, AFTER
sleep.commandhas run, flip the flag with the bypass:credo-autonomy-off.sh --after-suspend. Only an explicit user "leave it on" justifies ending withcredo-autonomy-off.sh --overrideinstead (that is a revocation - clear the directive too). Never end a directive run with a barecredo-autonomy-off.sh; it is designed to refuse.
Distinction: "all work genuinely completed / built" stays a high ntfy (come see results).
Only the nothing-was-buildable case uses default. Both are end-of-run and feed the same
power-down gate below.
Power down the machine at the end (I9)
The machine power-down can be EITHER suspend (standby / suspend-to-RAM) OR hibernate
(suspend-to-disk), per sleep.mode; refer to it generically as "power down / sleep the
machine". The global "never auto power-down" rule lives HERE now, scoped by mode:
- Non-autonomous modes (active, passive): NEVER auto power-down. Only sleep the machine on an explicit user request.
- Autonomous mode: the end-of-run triggers are EITHER everything is done (which includes an
empty buildable queue - see the section above), OR a showstopper occurs, OR the weekly axis
hits its power-down trigger. On the weekly axis the reset is NOT
a default showstopper: first PREFER the credo
budgetskill's weekly pause-and-resume (when the reset is near - same local calendar day - and weekly is at or aboveswitch_percent, pause via chained ScheduleWakeup across the reset and resume with a fresh weekly budget). Only the weekly last-resort net (99 percent) or a pause path that does not apply (the reset is on a different calendar day) reaches an end-of-run trigger on the weekly axis. The weekly triggers are set by the credobudgetskill; this skill owns what happens on a trigger - and whether that powers down the machine is gated below.
Power-down is OFF by default - it must be opted into (server-safe), OR ordered for this
session via an explicit suspend directive. Whether an end-of-run trigger sleeps the machine is
decided by the combined gate below (sleep.enabled true OR a set directive, plus a non-empty
sleep.command):
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get sleep.enabled
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get sleep.command
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-directive.sh" get
Combined end-of-run gate. The power-down fires when ALL hold: autonomous mode AND the
buildable queue is empty (fresh-listing backstop above) AND (sleep.enabled is true OR an
explicit suspend directive is set for this session) AND sleep.command is non-empty. A set
directive OVERRIDES sleep.enabled: false (the server-safe default): it is the user's
explicit, durable order to power down at end-of-run, and announced = committed. The override
does NOT extend to a missing sleep.command - with no command the MISCONFIG guard below still
wins (end cleanly, warn, never guess a command). The directive persists until an explicit
revocation; user presence does NOT revoke it (see the presence carve-out below).
sleep.enabledfalse (the DEFAULT) AND no suspend directive set: NEVER power down the machine. This is what keeps a SERVER running autonomous work from being powered down unexpectedly. On every end-of-run trigger (all done / showstopper / weekly cap reached) do NOT sleep - instead end the autonomous run CLEANLY viacredo-autonomy-off.shand send ahighntfy stating why (run complete, showstopper, or weekly cap reached). The machine stays on. BUT if a suspend directive IS set, the override applies: run the power-down procedure below (providedsleep.commandis non-empty), exactly as ifsleep.enabledwere true.sleep.enabledtrue (opt-in, personal machine only): run the power-down procedure below (veto window, double-fire protection, secure-work-first, then run the EXACT command fromsleep.command) on those same end-of-run triggers.- MISCONFIG guard: if
sleep.enabledis true butsleep.commandis EMPTY, that is a misconfiguration. Do NOT guess or hardcode a command. End the run cleanly viacredo-autonomy-off.shand send ahighntfy warning that sleep is enabled but no command is configured (re-run/credo:setup). Never sleep the machine on a guessed command.
Default OFF means autonomous work never powers down the machine unless the user opted in at
setup (/credo:setup). The weekly pause-and-resume path (budget skill) is unaffected either
way - it never powers down anyway; this gate governs only the last-resort 99 net and the
end-of-run / showstopper power-down.
Power-down procedure (only when the combined end-of-run gate above holds - (sleep.enabled
true OR a suspend directive is set) AND sleep.command non-empty; the directive path routes
here too, so this is NOT re-gated on sleep.enabled alone;
with retry plus timestamp-based success detection so a repeated trigger cannot fire the
power-down twice and a successful sleep is never miscounted as a failure):
Send an ntfy
highannouncing the pending power-down and open a veto window -windows.veto_minutes(default 20):"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get windows.veto_minutesDuring the veto window, watch for the user coming back. If the user responds or otherwise signals presence, CANCEL the power-down - do not sleep the machine out from under an active user.
Before powering down, make sure work is secured (git-push policy and, where relevant, the credo
compact-plussecuring) so nothing is lost across the sleep.Retry with success detection (applies to BOTH power-down modes -
suspendon native Linux andhibernateon WSL / Windows). Read the three thresholds from config, with the named defaults as fallback:"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get sleep.retry_count # default 3 "${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get sleep.retry_spacing_s # default 30 "${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get sleep.success_gap_min # default 5BEFORE the first power-down attempt, write the pending-suspend timestamp marker:
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-mark.sh" writeThen run the EXACT command from
sleep.command(read via the config above) to power down. Do NOT hardcode or guess the command - it is platform- and mode-specific and set at setup.Retry the command up to
sleep.retry_counttimes (default 3), waitingsleep.retry_spacing_sseconds (default 30) between attempts - but ONLY while the machine is still obviously awake. A further attempt is made only when we clearly did NOT fall asleep (the turn kept running); the moment the machine actually sleeps, the process is frozen and no further attempt is issued.
Success detection on the next turn / wakeup (this replaces the old double-fire flag). Ask the helper how long ago the marker was written and compare the jump:
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-mark.sh" elapsed # seconds, or exit != 0 / empty if no markerIf the elapsed jump is GREATER than
sleep.success_gap_minminutes (default 5, set deliberately well above the retry window) - the helper reports seconds, so compareelapsed_seconds > success_gap_min * 60- the machine really slept - the power-down SUCCEEDED. Clear the marker, drop the power-down intent, and do NOT re-suspend and do NOT score it as aborted / failed:"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-mark.sh" clearIf the marker is absent (helper exits non-zero / prints nothing), there is no pending power-down - do nothing.
If a user interrupt arrives right after waking (a real user message, which also turns autonomy off), do NOT re-suspend - clear the marker and stay awake for the user.
Only a small elapsed jump (at or below
sleep.success_gap_min) with the intent still open and no user present means the earlier attempts did not take effect - only then may the power-down be attempted again under the same retry budget.
Never power down the machine on your own initiative outside these autonomous triggers.
Suspend directive: persistence, presence, and the attended/unattended split
The suspend-on-idle directive (stored by credo-suspend-directive.sh, re-injected every
prompt by the session-mode inject hook) is the durable memory that the user ORDERED a
power-down at end-of-run. It feeds the combined end-of-run gate above; these rules keep it from
being silently lost - the exact failure that motivated it (a standing AFK+suspend order was
dropped on re-invoke, and the agent read user presence as "better hold off" and never
suspended even though it had announced it would).
- Persistence. The directive lasts the whole session and survives re-invokes of
/credo:session-autonomousand context compaction. A later invocation with no argument does NOT clear it. It is cleared ONLY by an explicit revocation (below). Ancredo-autonomy-offat end-of-run does NOT delete it either - it must outlive each run. - Announced = committed (hard rule). If you declared in the read-back that you will power down, you MUST carry it out at end-of-run. A read-back that promises a power-down is a commitment, not a maybe. Do not announce a suspend and then not do it.
- Presence does NOT revoke it (carve-out). Active user fixes, context messages, or other user presence DURING the build phase do NOT clear the directive. The user being at the keyboard while you build is not a cancellation of the end-of-run suspend they ordered. The 20-minute veto window right before the actual power-down (see the power-down procedure) REMAINS the intervention chance: the user can cancel there. This is not a contradiction - presence mid-build keeps the directive; a veto in the window cancels this one power-down.
- Anti-self-talk (hard rule against the reported failure). You may NOT reason yourself out of a set directive by reading user presence as an implicit "they probably do not want the suspend after all". Presence is not a silent cancellation. When the directive is set and the veto window passes with no cancellation, you power down - full stop.
- Explicit revocation = a natural-language user statement that clearly cancels the order
("no suspend", "do not power down", "leave it on", German "kein suspend", "lass an"). On such
a statement run
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-suspend-directive.sh" clear. Nothing else clears it.
Trigger split - how end-of-run reaches the power-down differs by attendance:
- Unattended (real autonomy / AFK): end-of-run reached with NO real user prompt in the
turn - the keep-alive wake fired, or a self-scheduled wake carrying the
[CREDO-AUTONOMY-WAKE]marker. This is the EXISTING path: send thehighntfy, open the 20-minute veto window (windows.veto_minutes), and power down if not vetoed. Do NOT use the Ask tool here - there is no one to answer it, so an Ask would run into the void. - Attended (autonomy-off with the user reachable): end-of-run reached because a real user
prompt ended the run and the user is present and reachable (a real user message just paused
autonomy via
credo-autonomy-clear.sh, as opposed to a[CREDO-AUTONOMY-WAKE]self-wake). Here, before powering down, you MUST FIRST ask via AskUserQuestion - e.g. "A suspend-on-idle directive is set for this session. Power down the machine now?" - and power down ONLY on a yes. On a yes, run the power-down procedure and end withcredo-autonomy-off.sh --after-suspendas its final step (the directive still stands, so a bare off would refuse). A "no" is an explicit revocation -> runcredo-suspend-directive.sh clear, after which a plaincredo-autonomy-off.sh(or--override) ends the run cleanly. This attended branch lives HERE, in the skill; the fail-safe hookcredo-autonomy-off.shnever runs this Ask and never touches the directive.
Authority order when the user is away
The common-core authority order (E5) applies, with the away-user branch active: self- resolve up to level 3 (the verbatim log and committed docs); if that is not enough, either raise a deferred question (above) when it truly needs the user, or fall back to a documented default (levels 4-5) and continue. Do not silently invent a requirement.
Git-push: atomic per slice
Per the common-core git-push policy, in autonomous mode commit ATOMICALLY per slice and
push per the granted authorization, so each unit of work is secured as it completes. The
commit-identity gate (credo budget skill) must pass before every commit. If commit or
push is forbidden by permissions, that is a SHOWSTOPPER for autonomous work - the work
cannot be secured - so warn via ntfy and stop; do not keep building unsecured work.
Budget-start read-back (mandatory before any autonomous start)
Before starting an autonomous run - always, not only overnight - the agent MUST give a read-back and only then start: the COMPLETE four-part read-back below on the FIRST start, and AT LEAST the short form on every start (see "Timing" below - never start without at least the short form). The full read-back has four parts (a scattered or late partial read-back is not acceptable):
(0) Read the real numbers first (mandatory - before naming ANY budget figure). Before you state ANY budget number in the read-back - a cap OR a live figure - you MUST read BOTH of these fresh, in this moment. A number that was not just read is not stated:
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-config.sh" get budget.schedule # the active profile's real caps, overrides included
"${CLAUDE_PLUGIN_ROOT}/scripts/credo-budget-read.sh" # live 5h% / weekly% + resets
- The binding cap axis and every cap value named in the read-back come ONLY from
budget.schedule(viacredo-config.sh) - the active profile's own rows, overrides included. NEVER a number from memory, and NEVER a number copied from the credobudgetskill's worked examples or defaults. - The live 5h% / weekly% come ONLY from
credo-budget-read.sh. If it exits 3 or 4 (no cache / stale cache), do NOT guess the live figures: report them honestly as "not readable (no/stale cache)", still name the static caps frombudget.schedule(always readable), and act conservatively. - Show the output (proof obligation, hard MUST). Reading fresh is not enough - a prose number is indistinguishable from remembered vs. read. The read-back MUST make the raw command output VISIBLE as the evidence: at minimum the applicable line
…(truncated)