nx/skills/rdr-audit/SKILL.md
Use when auditing a project's RDR lifecycle for silent-scope-reduction frequency, or when inspecting or managing scheduled periodic audits
npx skillsauth add hellblazer/nexus rdr-auditInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Wraps the canonical audit pattern proven in Phase 1b (RDR-067) as a one-command skill. Delegates the classification work to the deep-research-synthesizer agent (sonnet). See registry.yaml.
Phase 2a scope: default-mode audit dispatch only. The list / status / history / schedule / unschedule management subcommands are added in Phase 2b (nexus-dqp.4) and are not implemented here.
/nx:rdr-audit (no argument → current project) or /nx:rdr-audit <project> — runs the audit<project>"claude -p '/nx:rdr-audit <project>' on the user's local machine (see Phase 4 scheduling templates)list / status <project> / history <project> / schedule <project> / unschedule <project> (Phase 2b)<project> → audit the named project (e.g., nexus, a public project the user owns)list → list scheduled audits (Phase 2b, read-only)status <project> → show next-fire timestamp + last-run outcome (Phase 2b, read-only)history <project> → list last N audit findings for a project (Phase 2b, read-only)schedule <project> → print platform-specific install commands (Phase 2b, print-only)unschedule <project> → print uninstall commands (Phase 2b, print-only)--no-transcripts — skip the transcript-mining pre-step entirely (fast path)When invoked with no positional argument, derive the target project name via this precedence chain:
git remote get-url origin — parse the repo name from the remote URL; strip the .git suffix and take the last path componentpwd basename if git remote fails, returns empty, or is ambiguousDerivation happens in the skill body before anything else runs. The derived name is what gets substituted into {project} in the canonical prompt.
The skill body resolves the absolute filesystem path to the target project's worktree so the canonical prompt can Glob files via fully-qualified paths. There is no universal convention for where users keep project worktrees, so the resolution precedence is:
/nx:rdr-audit /srv/work/ART) OR a path containing a /, use it directly and derive the project name from its basename.NEXUS_PROJECT_ROOTS env var: colon-separated list of directories under which the user keeps project worktrees. Example: NEXUS_PROJECT_ROOTS="$HOME/src:$HOME/work". The skill body expands ~ and $HOME, probes each root for a child directory matching the project name, and uses the first existing match.NEXUS_PROJECT_ROOTS is unset): $HOME/git, $HOME/src, $HOME/projects, $HOME/code, $HOME/work, $HOME/dev, $HOME/Documents/git. None of these are authoritative — they are common conventions, not assumptions. Users whose project roots are elsewhere should set NEXUS_PROJECT_ROOTS.rdr_process + RDR cross-references. Surface a user-visible note: "No local worktree for <project> found under NEXUS_PROJECT_ROOTS or default candidates; proceeding with T2 evidence only. Set NEXUS_PROJECT_ROOTS to restore file-based evidence."The resolved absolute path is what gets substituted into {project_path} in the canonical prompt. The relative project name goes into {project} separately for display purposes. Never let the canonical prompt Glob a relative path — it will resolve against the main session's CWD (not the target project) and silently audit the wrong files, as surfaced during RDR-067 Phase 5a MVV first-attempt anomaly.
Transcript mining is NOT delegatable to subagents. The ~/.claude/projects/*.jsonl tree is not efficiently scannable from a subagent context — subagents do not have the main session's working directory, cannot traverse the directory efficiently with their tool budget, and the JSONL line lengths cause truncation in Grep tool output. The main session must gather transcript excerpts BEFORE dispatching the deep-research-synthesizer agent.
This invariant was verified in RDR-067 Phase 1b (T2 nexus_rdr/067-spike-disposition id 754). Violating it means the subagent receives an empty evidence layer and degrades silently.
Pre-step flow:
--no-transcripts was passed → skip mining, leave the slot empty, proceed to dispatch. The canonical prompt explicitly supports the empty-slot degraded case.ls ~/.claude/projects/-Users-<username>-git-<project>/ (path-mangled from the project's git worktree location). If the directory doesn't exist → leave the slot empty and proceed.silent scope reduction, composition failure, meta-RDR, failure mode).design mistake, latent, the plan was wrong) or a reopen decision.{transcript_excerpts} substitution block with session ID and line numbers preserved as citations.Fast path: if the target project has no ~/.claude/projects/* directory, or --no-transcripts was passed, skip the entire pre-step and dispatch with an empty {transcript_excerpts} block. Phase 1b validated that the prompt handles the empty case cleanly.
The skill embeds the pinned canonical prompt from T2 at dispatch time:
mcp__plugin_nx_nexus__memory_get(project="nexus_rdr", title="067-canonical-prompt-v1") — loads the v1 prompt (ttl=0 permanent; reference by stable title only — do not pass any runtime numeric id as a parameter){project} with the derived project name (bare name, for display){project_path} with the resolved absolute worktree path (see §Project Worktree Path Resolution) — this MUST be an absolute path with no tilde, no $HOME, no relative components. The canonical prompt uses {project_path} wherever it Globs evidence files.{transcript_excerpts} with the pre-step block (empty if fast path)Do NOT inline the canonical prompt text into this skill file — the prompt is the single source of truth in T2 and the skill references it by stable title. Updating the prompt is a T2 memory_put upsert, not a skill edit.
mcp__plugin_nx_nexus__scratch(
action="put",
content='{"targets": [{"tumbler": "1.1.771", "link_type": "cites"}], "source_agent": "deep-research-synthesizer"}',
tags="link-context"
)
{project} + {transcript_excerpts}memory_put to persist the full output. Subagents do NOT reliably self-persist; this was observed in 3/3 Phase 1b spike runs where subagents acknowledged persistence instructions but never called memory_put. The skill body itself must own this step.
mcp__plugin_nx_nexus__memory_put(
project="rdr_process",
title="audit-<project>-<YYYY-MM-DD>",
ttl=0,
tags="rdr-audit,<project>,audit",
content=<full subagent output with next_expected_fire timestamp header>
)
memory_search(project="rdr_process", query="audit-<project>") to find prior audits. If this audit contradicts a prior one (different verdict category OR different dominant drift category), flag the discrepancy for user review before returningFive management subcommands let users and agents inspect and manage scheduled audits from inside Claude Code without shelling out to OS primitives manually. Invoked as the first positional argument: /nx:rdr-audit list, /nx:rdr-audit status <project>, etc. If the first token is not one of the reserved subcommand words, the argument is treated as a project name and the skill routes to the default audit-dispatch flow instead.
The five subcommands split into two disjoint safety classes:
Read-only: list, status, history
claude -p, CCR remote agentlaunchctl load, no crontab -ememory_put, no memory_delete, no mutation of any T2 recordlaunchctl list + crontab -l) and T2 state (memory_list on rdr_process) taken before and after a read-only invocation should be byte-identicalPrint-only: schedule, unschedule
launchctl load, must not run launchctl unload, must not write .plist files to ~/Library/LaunchAgents/, must not edit crontab via crontab -e, must not spawn any process that installs or modifies scheduled triggers~/Library/LaunchAgents/, the user's crontab, and running-process list before and after — confirms no files written, no processes spawned, no scheduled triggers modifiedSystem-level installs are explicitly the user's step. The skill never runs them automatically. This split protects users from unauthorized privileged OS changes while still making the management surface inspectable from any session.
list (read-only)Enumerate all scheduled rdr-audit triggers on the local machine across both macOS launchd and Linux cron.
Behavior:
launchctl list | grep rdr-audit (macOS) — capture lines matching com.nexus.rdr-audit.*crontab -l 2>/dev/null | grep rdr-audit (Linux) — capture matching linesproject, platform (launchd/cron), schedule expression, next-fire timestamp (when available)No audits scheduled and exit 0This subcommand calls only the two read commands above. It does not call launchctl load, launchctl unload, crontab -e, or any write-variant command. It does not touch T2 at all.
status <project> (read-only)Show next-fire time + last-run outcome for a specific project's audit.
Behavior:
launchctl print com.nexus.rdr-audit.<project>.90d (macOS) OR parse the matching crontab -l line (Linux) to extract the next-fire timestamp. If neither finds a trigger, the subcommand reports No audit scheduled for <project> and exits 0.mcp__plugin_nx_nexus__memory_search(project="rdr_process", query="audit-<project>") — find the most recent entrymcp__plugin_nx_nexus__memory_get(project="rdr_process", title=<found title>) — read the last-run contentProject: <project>
Scheduled: <platform> — next fire <timestamp>
Last run: <date> — <verdict> — <rate> — <confidence>
Drift: <distribution>
Read-only: no memory_put, no launchctl load, no crontab edit, no file writes. T2 reads via memory_search and memory_get only. OS reads via launchctl print or crontab -l only.
history <project> (read-only)List the last N audit findings for a project from T2.
Behavior:
mcp__plugin_nx_nexus__memory_search(project="rdr_process", query="audit-<project>") — enumerate matching entries--count N override)memory_get the entry contentRead-only: exclusively T2 memory_search + memory_get. No OS interaction. No T2 writes.
schedule <project> (print-only)Print the platform-specific install commands for the user to review and run themselves manually. Does not execute the install.
Behavior:
uname -s (Darwin → macOS, Linux → Linux)<PROJECT> substituted, and print together with the launchctl load instruction the user will run<PROJECT> substituted, and print together with the crontab -e instruction the user will runCadence note (macOS vs Linux): launchd's StartCalendarInterval does not support exact 90-day intervals natively. The macOS plist template below fires on the 1st of each month at 03:00 local time — approximately 30-day cadence, not the RDR-067 target 90-day cadence. This is the closest practical approximation launchd supports without manual month-list scheduling. The Linux crontab template (shown after the plist) uses 0 3 1 */3 * which IS a true 90-day cadence (1st of every 3rd month). macOS users who want true quarterly cadence have three options: (a) accept the monthly approximation (the failure mode occurs ~1-2× per month, so monthly sampling is strictly finer-grained than the target, not coarser), (b) add a month-list StartCalendarInterval with explicit Jan/Apr/Jul/Oct entries, or (c) switch to a user-level cron daemon (pcron, gcron) and use the Linux crontab template instead. When the skill prints this plist via /nx:rdr-audit schedule <project>, it prints this cadence note alongside the template so the user is not surprised.
macOS plist template (substitute <PROJECT> with the target project name; coordinate with scripts/launchd/com.nexus.rdr-audit.PROJECT.plist from Phase 4):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTD/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.nexus.rdr-audit.<PROJECT>.90d</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/claude</string>
<string>-p</string>
<string>/nx:rdr-audit <PROJECT></string>
</array>
<key>StartCalendarInterval</key>
<dict>
<key>Day</key><integer>1</integer>
<key>Hour</key><integer>3</integer>
<key>Minute</key><integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/tmp/rdr-audit-<PROJECT>.log</string>
<key>StandardErrorPath</key>
<string>/tmp/rdr-audit-<PROJECT>.err</string>
</dict>
</plist>
Linux crontab template (substitute <PROJECT>; coordinate with scripts/cron/rdr-audit.crontab from Phase 4):
0 3 1 */3 * /usr/local/bin/claude -p '/nx:rdr-audit <PROJECT>' >> ~/.local/state/rdr-audit-<PROJECT>.log 2>&1
Printed installation instructions (what the user then runs themselves):
macOS:
1. Save the plist above to ~/Library/LaunchAgents/com.nexus.rdr-audit.<PROJECT>.90d.plist
2. Run: launchctl load ~/Library/LaunchAgents/com.nexus.rdr-audit.<PROJECT>.90d.plist
3. Verify: launchctl list | grep rdr-audit
Linux:
1. Run: crontab -e
2. Append the line above
3. Save and exit the editor; cron picks up the change automatically
4. Verify: crontab -l | grep rdr-audit
The skill body itself must not write the plist file, must not execute launchctl load, must not edit the crontab via crontab -e, and must not spawn any privileged OS process. The templates are printed text; all state changes are the user's explicit step.
unschedule <project> (print-only)Print the platform-specific uninstall commands for the user to review and run themselves manually. Does not execute the uninstall.
Behavior:
uname -slaunchctl unload + rm commands the user will runcrontab -e instructions and the line to removemacOS uninstall commands (printed for user to run):
launchctl unload ~/Library/LaunchAgents/com.nexus.rdr-audit.<PROJECT>.90d.plist
rm ~/Library/LaunchAgents/com.nexus.rdr-audit.<PROJECT>.90d.plist
Linux uninstall instructions (printed for user to run):
1. Run: crontab -e
2. Remove the line matching: /nx:rdr-audit <PROJECT>
3. Save and exit
4. Verify: crontab -l | grep rdr-audit # should show nothing
The skill body itself must not execute launchctl unload, must not write or delete plist files, must not edit crontab via crontab -e, and must not spawn any privileged OS process. The commands are printed text the user runs manually.
The first positional argument may be either a reserved subcommand word or a project name. Rule: check the reserved subcommand set first (list, status, history, schedule, unschedule) — if the first token matches any of these exactly, route to the named subcommand. Otherwise treat the first token as a project-name argument and route to the default audit-dispatch flow. This prevents a project literally named list from being hijacked to the listing subcommand (the user can use /nx:rdr-audit <full-qualified-name> or rename the project).
The plist and crontab templates above are the canonical shape. Phase 4 (nexus-dqp.7) ships the same templates as sibling files under scripts/launchd/ and scripts/cron/. Both bead paths converge on the same format: the file is the source of truth at install time; the skill's schedule subcommand renders the equivalent text from the skill body for immediate user review. Updating the template means updating both locations — the sibling script file and this skill section — in one PR.
The skill body MUST own the memory_put step, not the subagent. This is an invariant from Phase 1b:
memory_put on their findingsmemory_put — all records had to be persisted by the main session after the dispatchThe root cause is not diagnosed (could be model-level instruction compliance, could be tool routing in subagent context, could be a budget ceiling heuristic). The Phase 2 resolution is structural: persistence is a skill-body responsibility. The subagent returns the audit text; the skill body parses it, formats the T2 record, and calls memory_put directly. Do NOT rely on the subagent to self-persist under any circumstances.
Use the Agent tool with standardized relay format. See RELAY_TEMPLATE.md for required fields and examples.
## Relay: deep-research-synthesizer
**Task**: Execute the RDR-067 canonical audit prompt against `<project>`. Output must conform to the `## Output format (REQUIRED)` section of the prompt (CA-1 structural criteria a-d).
**Bead**: none (or the invoking bead ID if triggered from planning work)
### Input Artifacts
- nx store: none
- nx memory: rdr_process/* (prior audits for this project), nexus_rdr/067-canonical-prompt-v1 (the canonical prompt)
- Files: `<project-worktree>/docs/rdr/post-mortem/*.md` (primary evidence; the skill body substitutes the absolute worktree path into the prompt via the `{project_path}` parameter before dispatch)
### Deliverable
Full audit output conforming to the canonical prompt's output-format contract:
- Sources consulted
- Sampling caveats
- Confirmed incidents in window (with all required fields) OR explicit VERDICT: INCONCLUSIVE block
- Frequency estimate with HIGH/MEDIUM/LOW confidence
- Drift-category distribution
- (Optional) Near-misses
- Recommendation (exactly one of VERIFIED / PARTIALLY VERIFIED / FALSIFIED / INCONCLUSIVE)
### Quality Criteria
- [ ] All four CA-1 structural criteria satisfied (a confirmed-or-inconclusive, b caveats, c frequency+confidence, d drift-category per incident)
- [ ] ≤25 tool calls (budget ceiling from Phase 1b)
- [ ] No unsolicited trailing relay sections ("Next Step", "Recommended Next Step", etc.)
- [ ] Respects the non-delegatable invariant — do NOT attempt to glob `~/.claude/projects/*` from within the subagent context
Task body: embed the full substituted canonical prompt (loaded via memory_get(project="nexus_rdr", title="067-canonical-prompt-v1"), with {project} and {transcript_excerpts} filled in) as the task content. The relay envelope above wraps the prompt — the prompt itself is the dispatch payload.
--no-transcripts / no transcript directory)nexus_rdr/067-canonical-prompt-v1 and substitutedrdr_process/audit-<project>-<YYYY-MM-DD> with ttl=0When the audit subagent reads T2 rdr_process, it ingests both prior audit outputs and individual incident filings from sibling projects. Sibling projects file cross-project incidents using the template at nx/resources/rdr_process/INCIDENT-TEMPLATE.md (Phase 3). The template has 6 frontmatter fields (project, rdr, incident_date, drift_class, caught_by, outcome) and 8 required narrative sections covering what was meant, what shipped, the gap, decision point, mechanism, what caught it, cost, and lessons.
Filings land in T2 as rdr_process/<project>-incident-<slug> with ttl=0 (permanent). The audit subagent picks them up via memory_list(project="rdr_process") + memory_search(project="rdr_process", query="<project>"). The template's drift_class enum values exactly match the sub-pattern taxonomy in the canonical prompt, so the subagent can classify filed incidents directly without translation.
See the template file for the full schema and ## How to file instructions.
Outputs generated across the audit flow:
next_expected_fire timestamp header for Phase 2b status subcommand use.rdr_process.This skill incorporates six signals surfaced by the Phase 1b spike (T2 nexus_rdr/067-spike-disposition):
memory_put — subagents do not reliably self-persist (0/3 Phase 1b runs called memory_put despite explicit instruction). Resolved by moving persistence to the skill body.--no-transcripts flag + automatic fast path when no transcript directory exists. Resolves the meta-session noise trap identified in Phase 1b.Two independent CA-1/CA-2 audit runs against nexus produced a false-positive SCOPE-REDUCED verdict on RDR-056 because 3/4 success-criteria checkboxes were unchecked — but the code had shipped all 4 features (probe_hit_rate in t3.py, search_clusterer.py, distance_threshold in config.py, hnsw:search_ef in doctor.py). The audit read RDR text but not code.
Fix: the canonical prompt (v1.2) now includes a mandatory code-verification gate for any non-CLEAN verdict. Before classifying PARTIAL or SCOPE-REDUCED, the auditor must Grep the project source for key identifiers from the success criteria. If the code ships the feature, the unchecked checkbox is a documentation gap, not a scope gap.
Code-verification result field for non-CLEAN verdictsSee T2 nexus_rdr/067-research-2-audit-methodology-false-positive (id 771) for the evidence.
development
Use when critiquing / auditing / reviewing a change set against decision history — tries the review plan library first (catalog lookup → decision-evolution traversal → extract → compare), falls through to /nx:query if nothing matches
documentation
Use when doing design / architecture / planning work that walks from prose (RDRs, docs, knowledge) into the modules implementing a concept
development
Use when surveying the plan library's runtime metrics to propose plans for promotion to a higher scope — advisory-only; dispatches the plan-promote-propose meta-seed (no lifecycle ops — those ship in RDR-079)
business
Use when inspecting plan runtime metrics or enumerating dimension-registry usage — dispatches plan_match with dimensions={verb:plan-inspect}; strategy:default reports per-plan metrics, strategy:dimensions reports registry usage counts