Install
$ agentstack add skill-itsalt-nacl-nacl-goal ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
Contract
Inputs this skill consumes:
- `
— required positional. One of the named aliases fromnacl-goal/aliases.md`
(wave:, fix:, validate:, reopened-drain, intake, conduct, custom), or the special invocations resume and abort .
--start— optional flag. Without it the preview-mode aliases (wave,fix,
validate, reopened-drain, custom) run in preview/dry-run mode only. The intake alias has the inverse default: autonomy ON, with --plan-only as the opt-out (see §intake alias UX below).
--tier=— optional override forcustomalias (mandatory for custom).--check-script=— path to executable check script forcustomalias (mandatory for custom).--description=""— optional label recorded in the run file.intake-only opt-out flags:--plan-only,--strict,--target=,--new-run. See §intakealias UX.
Outputs this skill produces:
- Without
--start: a preview block containing the full resolution: alias, tier, soft budget,
checkscript path, GOALPROOF template, human gates, permissions denylist, and (for Tier L/XL) estimated dollar cost from nacl-goal/pricing.json. The exact --start command to copy-paste.
- With
--start(2.10.0, Tier S/M): a warning that autonomous execution is 2.10.1 functionality,
then issues /goal with the composed condition. Does NOT produce a .tl/goal-runs/ file in 2.10.0.
- With
--start(2.10.0, Tier L/XL): structured refusalREFUSE_TIER_NOT_YET_ENABLED. - Refusal block (any tier, any phase) when a Tier-C gate is detected statically.
Downstream consumers of this output:
- Human user (preview, refusal, run summary)
.tl/goal-runs/— run files written on--start(enforced from 2.10.1)
Two-phase invocation (Architecture §2)
/goal starts a turn immediately on invocation. The preview/confirm UX lives outside /goal, in this wrapper:
/nacl-goal # preview only — no /goal issued, no turn consumed
/nacl-goal --start # issues /goal with composed GOAL_PROOF condition
Preview output must include all of:
- Resolved alias name and canonical form
- Tier and full soft budget (turns, hours, observed token target) from the tier table below
check_scriptpath and how it is invoked each turn- Completion condition verbatim (including the GOAL_PROOF instruction block)
- Human gates that would block this alias (or
"none detected") - Permissions denylist that will be enforced
- For Tier L/XL: estimated dollar cost at current model pricing from
nacl-goal/pricing.json - The exact
--startcommand to copy-paste
--start behavior in 2.10.0
- Tier S / Tier M: Issues
/goalwith the composed GOAL_PROOF condition, but emits this
warning before doing so:
`` WARNING (2.10.0): Autonomous execution via /nacl-goal --start is 2.10.1 functionality. In 2.10.0, /goal is issued but .tl/goal-runs/ write, concurrent-execution lock, crash/resume, and runtime gate detector are NOT active. Run interactively and monitor. ``
- Tier L / Tier XL: Refuses with
REFUSE_TIER_NOT_YET_ENABLED:
`` REFUSE_TIER_NOT_YET_ENABLED Tier L and XL autonomous execution is not enabled in 2.10.0. Use /nacl-goal (preview) to inspect the plan. Autonomous Tier L/XL arrives in 2.10.1. ``
Tier table — v0 calibration defaults (Architecture §13)
All three columns are soft. /goal cannot hard-enforce them. A true hard cap requires an external runner or Stop-hook script (future work, 2.10.2+). Do not run XL unattended overnight in 2.10.0 or 2.10.1.
| Tier | turnssoft | wallclocksoft | observedtoken_target | |------|------------|-----------------|----------------------| | S | 150 | 2 h | 3,000,000 | | M | 500 | 6 h | 8,000,000 | | L | 1,200 | 16 h | 20,000,000 | | XL | 3,000 | 36 h | 50,000,000 |
Turn and wall-clock are surfaced through GOAL_PROOF every turn and trigger GOAL_BUDGET_EXHAUSTED via the in-condition instruction. To be calibrated in 2.10.2 from aggregated .tl/goal-runs/.
GOAL_PROOF protocol (Architecture §1)
Every alias generates a /goal condition that instructs the primary session to run the alias check script at the end of every turn and print a block of this exact shape immediately after the raw command output:
GOAL_PROOF
alias:
tier:
check_command:
result: GOAL_OK | GOAL_NOT_OK | GOAL_BLOCKED | GOAL_BUDGET_EXHAUSTED
evidence:
- :
- :
turns_so_far:
observed_tokens:
elapsed:
END_GOAL_PROOF
The evaluator (Haiku 4.5 by default) is transcript-only — it cannot run tools, read files, or execute commands. GOALPROOF surfaces machine-checkable state into the transcript so the evaluator's only job is: "did the last block have result == GOALOK AND does .tl/goal-runs/.md exist."
This block is a wire format. Field renames and delimiter changes are major version bumps. No narrative is permitted between the command output and the GOAL_PROOF block. See docs/guides/goal-proof-protocol.md for full schema, semantics, and examples.
Alias resolution and check scripts (Architecture §3)
Aliases and their binding contracts are defined in nacl-goal/aliases.md. Do not duplicate alias definitions here — reference that file.
Check scripts shipped in 2.10.0 (stubs; truth-source wiring in progress):
nacl-goal/checks/wave.sh
nacl-goal/checks/fix.sh
nacl-goal/checks/validate.sh
nacl-goal/checks/reopened-drain.sh
Check scripts shipped in 2.10.1 (intake ships in PR1; the others remain deferred):
nacl-goal/checks/intake.sh --run-id # ✅ PR1
nacl-goal/checks/stubs-cleanup.sh # deferred
nacl-goal/checks/migrate-canary.sh # deferred
nacl-goal/checks/feature.sh # deferred
nacl-goal/checks/probe-stop-signals.sh (invoked each turn) # deferred
Check script shipped in 2.18.0 (conduct multi-cluster orchestrator):
nacl-goal/checks/conduct.sh --run-id # ✅ scans clusters/*/
Every check script:
- Takes its positional args per the contract in
nacl-goal/aliases.md - Reads its truth source directly (graph via Cypher, registry file, YouGile API, test runner)
- Prints stable, grep-friendly output followed immediately by a GOAL_PROOF block
- Always exits 0 — the evaluator cannot see exit codes; GOAL_PROOF carries the actual status
Structured refusal flow (Architecture §5)
Tier-C refusals fire at preview time wherever statically possible (by alias identity). The runtime gate detector catches dynamic crossings (2.10.1).
Every refusal must:
- Name the specific gate by its
REFUSE_*code fromnacl-goal/refusal-catalog.md - Cross-reference
nacl-tl-core/references/gate-fire-catalog.md - Offer a split-mode suggestion (interactive skill then wrapper)
- Print copy-paste commands for the interactive path
User-facing rendering follows the rendering rule in nacl-goal/refusal-catalog.md: lead with the plain-language reason + copy-paste fallback; the gate code is a trailing tag, not the headline; and step numbers / Tier-C never appear in user-facing text. (Items 1–2 above are satisfied by the trailing tag and the internal cross-reference — they are not the headline.)
Refusal codes (full catalog in nacl-goal/refusal-catalog.md):
REFUSE_HUMAN_GATE_BA_SA_HANDOFF
REFUSE_HUMAN_GATE_SA_PHASE_CONFIRMATION
REFUSE_HOTFIX_JUDGMENT
REFUSE_POST_CANARY_RETROSPECTIVE
REFUSE_PRODUCTION_MUTATION
REFUSE_UNTIERED_CUSTOM_GOAL
REFUSE_UNTRUSTED_WORKSPACE
REFUSE_HOOKS_DISABLED
REFUSE_CONCURRENT_GOAL_LOCKED
REFUSE_DANGEROUSLY_SKIP_PERMISSIONS
REFUSE_TIER_NOT_YET_ENABLED
Refusal codes are part of the wire format. Renaming or removing a code is a major version bump for /nacl-goal.
Permissions denylist (Architecture §6)
/nacl-goal runs only in default permissions with explicit approvals, OR in auto mode with the NaCl allowlist active.
Full text in docs/guides/goal-permissions.md. Brief summary:
Never allowed under any alias:
--dangerously-skip-permissions(triggersREFUSE_DANGEROUSLY_SKIP_PERMISSIONS)- Any mode that disables hooks (triggers
REFUSE_HOOKS_DISABLED) - Any workspace where workspace trust is not granted (
REFUSE_UNTRUSTED_WORKSPACE) git pushto any remotegit mergeintomain,master, orrelease/*- Any release-publishing action (
npm publish,gh release create, etc.) - Production DB migrations
rm -rfoutside the current workspace- Editing
.env*, secrets, credentials,.ssh/,~/.aws/,~/.config/gh - Changing CI/CD configuration or credentials
- Calling third-party paid APIs with side effects beyond test budget
Per-alias allowlist (positive grants):
- Local test execution
- Graph reads and writes scoped to current project
- Branch commits
gh pr create(but nevergh pr merge)- YouGile column moves within the project board
Custom alias (Architecture §12)
/nacl-goal custom \
--tier= # mandatory
--check-script= # mandatory; must exist, be executable,
# and produce GOAL_PROOF-compatible output
--description="" # recorded in run file
--start # must be a separate invocation
Custom without --check-script returns REFUSE_UNTIERED_CUSTOM_GOAL. Custom without --tier returns REFUSE_UNTIERED_CUSTOM_GOAL. Custom may not target paths matching the Tier-C catalog in nacl-goal/gate-fire-detector.md.
intake alias (2.10.1 — autonomous goal orchestrator)
intake is the FIRST alias with default_mode: autonomous. Where the four 2.10.0 aliases (wave, fix, validate, reopened-drain) require an explicit --start to issue /goal, intake issues /goal by default and provides opt-outs for previewing or strict mode.
This is intentional UX: /nacl-goal intake "" should be the short, normal invocation. The user shouldn't need to remember internal flags or gate names to drive a goal autonomously to a staging stand. See [[feedback-autonomy-default-ux]] for the design rationale.
intake UX
/nacl-goal intake ""
Default behavior:
• autonomous execution is ON
• standard safe-exception envelope is ON (see nacl-goal/envelope.md)
• target = staging if config.yaml → deploy.staging.url exists,
otherwise PLAN_BLOCKED_STAGING_REQUIRED_BUT_MISSING
• branch_mode = current when invoked from a non-production branch:
atoms run ON the branch you are standing on, commits stay local,
ONE push at DELIVER (push_cadence = deferred). The preview prints
a one-line notice: "Running on your branch ; one push at
deliver; do not commit to this branch while the run is active."
From main/master/release/* the production refusal still fires —
create a working branch first.
• atoms BUG / TASK / FEATURE_SMALL run on that single branch, one PR
• atoms FEATURE_HEAVY → PLAN_BLOCKED with planning artifacts (no silent split)
• uncommitted changes (another agent's WIP) do NOT refuse the run in
branch_mode=current — see Flow step 3 "Smart WIP" for the
file-overlap protocol
Opt-outs (each disables a slice of the default):
--plan-only write planning artifacts only; no /goal, no branch, no PR,
no exception YAML, no source-code changes
--strict disable default safe-exception envelope; pre-flight refuses
if plan predicts a gate would need envelope auto-authorization
(PLAN_BLOCKED_STRICT_REQUIRES_INTERACTIVE_FLOW)
--branch=current run on the currently checked-out branch (default when on a
non-production branch)
--branch=new pre-2.14 behavior: create feature/goal-; requires
a clean worktree (PLAN_BLOCKED_DIRTY_WORKTREE applies)
--push=deferred atoms commit locally; single push at DELIVER (default when
branch_mode=current)
--push=per-atom push after every atom; PR opens on first push (default when
branch_mode=new — pre-2.14 behavior)
--push=none no push at all; run ends with local commits; ONLY valid with
--target=dev-only (with staging it is a usage error rejected
at argument parsing, before step 0 — no artifacts written);
deliver later with /nacl-tl-deliver
--target=staging require staging (default)
--target=dev-only local verify + PR only; final message MUST NOT claim staging
delivery; dev_verified is asserted via local /nacl-tl-verify
--new-run force fresh run-id even if goal_fingerprint matches an existing
run; does NOT close or reuse prior PR in 2.10.1
--budget= optional budget override (default Tier M: 200 turns / 3h / 4M tokens)
Backward-compat invariant: `--branch=new` reproduces the pre-2.14 flow
byte-for-byte (new goal branch, per-atom pushes, dirty-worktree refusal).
The default changed ONLY for invocations from an existing feature branch.
intake Flow (14 steps)
The Claude session running /nacl-goal intake executes the following flow. For per-file schemas see nacl-goal/plan-lock-schema.md. For artifact locations and idempotence see nacl-goal/run-artifacts.md. For the exception envelope see nacl-goal/envelope.md. For gate prediction see nacl-goal/gate-prediction.md. For retry semantics see nacl-goal/retry-policy.md. For regression diff see nacl-goal/regression-schema.md.
0. PRIVACY / IGNORE PRECHECK
verify .tl/goal-runs/ AND .tl/exceptions/goal-runs/ are gitignored
(use `git check-ignore` from project_root)
if either is NOT ignored:
→ PLAN_BLOCKED_GOAL_ARTIFACTS_NOT_GITIGNORED
The 2.10.1 wrapper does NOT auto-patch .gitignore. The user must do it.
Writing PII (user email, free-text goal, image refs) into a non-ignored
directory is irreversible if the user pushes by accident.
1. INIT_RUN
compute goal_fingerprint (see run-artifacts.md §Goal fingerprint)
acquire flock on .tl/goal-runs/index.lock (timeout 30s; else
PLAN_BLOCKED_INDEX_LOCK_BUSY)
consult index.json per the re-invocation rules in run-artifacts.md
(RESUME for transient interruptions; refuse for non-resumable terminal
states unless --new-run)
run_id = goal-intake--
mkdir .tl/goal-runs//{atoms/, planning/}
write request.json, budget.json
append index.json entry (state: "init", resumable: true)
atomic rename; release flock
2. RESOLVE_TARGET
--target=staging or default + deploy.staging.url present → deploy_target = staging
--target=dev-only → deploy_target = dev-only (WARN)
else → PLAN_BLOCKED_STAGING_REQUIRED_BUT_MISSING
3. PRECHECKS (Tier-C; /goal not yet issued)
on main/master/release/* → PLAN_BLOCKED_UNSAFE_PRODUCTION_MUTATION
(fires regardless of branch_mode; create a working branch first)
resolve branch_mode / push_cadence:
--branch absent → branch_mode = current (we are on a non-production branch)
--branch=new → branch_mode = new
push_cadence = --push if given, else deferred (current) / per-atom (new)
Smart WIP (branch_mode=current):
preexisting_dirty_files[] = paths from `git status --porcelain`
(including untracked); recorded in plan.lock.json at step 5
non-empty does NOT refuse — uncommitted files are presumed to be
another agent's in-flight work in the shared worktree. They are
never staged, never committed, never reverted by the goal run.
overlap resolution happens at step 5 (needs classified atoms);
hard runtime backstop at step 9 (commit-time collision gate)
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [ITSalt](https://github.com/ITSalt)
- **Source:** [ITSalt/NaCl](https://github.com/ITSalt/NaCl)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.