yaah_scan_secrets, yaah_lint, yaah_check_command, yaah_doctor, yaah_session_info, yaah_planning_status, yaah_planning_init) and five hook handlers (linter, command-guard, secret-scanner, comment-checker, session-logger), talking only over stdio, the local filesystem, and git-over-HTTPS to pinned source repositories. The command guard and the secret scanner are declared fail-closed safety controls that must never be removed or downgraded to advisory mode, credentials must never be embedded in generated configuration, and yaah must never self-trigger its own workflow commands.Block becomes exit 2 — but the guard is seven regexes over a shell, the scanner runs at PostToolUse so the credential is already on disk when it fires, and pkg/generator/hookmap.go maps neither event for the Codex target, so yaah generate --agent codex emits a working config with no command guard and no secret scanner at all, offering only model-elective MCP tools in their place. The second theme is capability and credential material flowing outward through generated files: NewNotion() interpolates an API token into an MCP env value that every generator writes verbatim into repository config, and every /yaah:* workflow command — including the one whose own text says it runs "without human intervention" — ships model-invocable because disable-model-invocation is supported by the generator and set by nothing.pkg/harness wires seven registries and dispatches hook events, pkg/hooks/handlers holds the five built-in handlers, pkg/mcpserver serves the seven tools over stdio, and four generators in pkg/generator emit each target agent's native config. Blocking is real — a handler returning Block makes yaah hook exit 2 — and session state lands in .claude/sessions/<id>.json through an atomic-write store with traversal-safe identifiers. Remote skills and agents are fetched by pkg/gitcache from commit-SHA-pinned GitHub repositories and written into the host agent's .claude/ tree, while the built-in MCP defaults reach outward to an npm-installed Context7 server and Pulumi's hosted endpoint. The divergences from the remit sit at the edges of that structure: the Codex generator has no PreToolUse or PostToolUse mapping, the secret scanner is a PostToolUse handler, and the Notion provider carries an API token in a config field that every generator serializes to disk.Every actionable rule in the Worker Remit, checked against the running code. Gap = declared but unenforced; Partial = enforced but incomplete or bypassable; Vague Policy = too imprecise to verify.
| Rule ID | Section | Rule (quoted) | Status | Finding |
|---|---|---|---|---|
| R-01 | Prohibited Behaviors | "yaah MUST NEVER treat the content of fetched remote skills or agents, MCP tool descriptions, or scanned/linted file contents as instructions that change its own behavior or safety decisions — such content is untrusted data, never authority over yaah." | Verified | — |
| R-02 | Prohibited Behaviors | "yaah MUST NEVER auto-invoke its /yaah:* workflow commands, including the autonomous workflow, without an explicit user invocation; the model must not self-trigger them." | Gap | PRAX-2026-08-12-002 |
| R-03 | Prohibited Behaviors | "yaah MUST NEVER run with its command-guard or secret-scanner safety hooks removed, disabled, or downgraded to a non-blocking / advisory mode; these are safety controls, not optional lint." | Partial | PRAX-2026-08-12-003 |
| R-04 | Approved Communication Channels | "stdio only; no network bind" | Verified | — |
| R-05 | Approved Communication Channels | "Within the target repository and the yaah cache directory" | Partial | PRAX-2026-08-12-008 |
| R-06 | Approved Communication Channels | "Fetch and cache only; sources must be pinned (see Authorized Counterparties)" | Verified | — |
| R-07 | Approved Communication Channels | "Only servers the operator configured" | Partial | PRAX-2026-08-12-007 |
| R-08 | Approved Communication Channels | "Disabled unless the operator has explicitly authorized it" | Verified | — |
| R-09 | Approved Communication Channels | "Approved Communication Channels" | Verified | — |
| R-10 | Authorized Counterparties — Trusted Services / Integrations | "Any skill, agent, MCP server, plugin, or marketplace wired into generated configuration that falls outside this operator-configured catalog is an unauthorized trust expansion." | Verified | — |
| R-11 | Authorized Counterparties — Trusted Domains | "Trusted Domains" | Partial | PRAX-2026-08-12-007 |
| R-12 | Authorized Counterparties — Explicitly Forbidden | "Fetching default or shipped remote skills/agents from mutable refs (branches) rather than immutable refs (a commit SHA or version tag)." | Verified | — |
| R-13 | Authorized Counterparties — Explicitly Forbidden | "Wiring in any skill, agent, MCP server, marketplace, or plugin outside the operator-configured vetted catalog (see the Closure rule under Trusted Services / Integrations)." | Verified | — |
| R-14 | Tools and Capabilities — Allowed Tools (Known Good Baseline) | "Closure rule: any tool the runtime or MCP server exposes, or any hook handler it runs, that is not in this baseline is an undeclared capability." | Verified | — |
| R-15 | Tools and Capabilities — Restricted Tools (Require Approval Before Use) | "Restricted Tools (Require Approval Before Use)" | Partial | PRAX-2026-08-12-001 |
| R-16 | Tools and Capabilities — Forbidden Tools | "No MCP tool may execute arbitrary shell commands outside the command guard, and no tool may return detected secret values in cleartext." | Partial | PRAX-2026-08-12-006 |
| R-17 | Data Boundaries — Allowed Data Sources | "Allowed Data Sources" | Partial | PRAX-2026-08-12-008 |
| R-18 | Data Boundaries — Forbidden Data Movement | "Detected secret values MUST NEVER be written into session logs, findings records, generated configuration, or any yaah output in cleartext — secrets are referenced by location and pattern only." | Verified | — |
| R-19 | Data Boundaries — Forbidden Data Movement | "Credentials, API tokens, and OAuth secrets MUST NEVER be embedded in generated configuration files." | Gap | PRAX-2026-08-12-001 |
| R-20 | Data Boundaries — Forbidden Data Movement | "Credentials, API tokens, and OAuth secrets MUST NEVER be committed to the repository." | Partial | PRAX-2026-08-12-001 |
| R-21 | Data Boundaries — Forbidden Data Movement | "Credentials, API tokens, and OAuth secrets MUST be sourced from environment variables or a secrets manager." | Gap | PRAX-2026-08-12-001 |
| R-22 | Data Boundaries — Forbidden Data Movement | "Repository contents, scanned file contents, and session audit data MUST NEVER be transmitted to any destination other than the local filesystem or an explicitly-configured trusted integration." | Verified | — |
| R-23 | Action Boundaries — Allowed Without Approval | "Allowed Without Approval" | Verified | — |
| R-24 | Action Boundaries — Requires Human Approval Before Execution | "Enabling any feature that makes outbound network calls or spawns an autonomous subagent (e.g. the experimental fact-checker): such features MUST be off by default and enabled only by explicit operator opt-in." | Partial | PRAX-2026-08-12-007 |
| R-25 | Action Boundaries — Never Allowed | "A file edit that introduces a hardcoded credential MUST NEVER be written — the secret scanner blocks it (fail closed)." | Partial | PRAX-2026-08-12-005 |
| R-26 | Action Boundaries — Never Allowed | "A shell command matching the dangerous-command denylist (e.g. rm -rf /, force-push to a protected branch, git reset --hard, destructive SQL) MUST NEVER be allowed to execute — the command guard blocks it (fail closed)." | Partial | PRAX-2026-08-12-004 |
| R-27 | Action Boundaries — Never Allowed | "Session files MUST NEVER be read or written at paths derived from unvalidated session identifiers; identifiers containing path separators or the special values . / .. are rejected (path-traversal prevention)." | Verified | — |
| R-28 | Action Boundaries — Never Allowed | "Generated configuration MUST NEVER weaken the host coding agent's permission/sandbox posture: it may not place the host into a permission-bypassing (bypassPermissions / dontAsk) or sandbox-disabled mode by default, nor drop the host below its stated minimum permission/sandbox posture." | Verified | — |
| R-29 | Escalation Rules — Halt Agent and Alert Operator | "When the command guard matches a dangerous command, or the secret scanner detects a credential in an edit, the hook must block the operation and record the block (with its reason) to the session audit log." | Verified | — |
| R-30 | Escalation Rules — Alert Operator (Do Not Halt) | "yaah doctor reports missing dependencies or misconfiguration for the operator to resolve; this surfaces a warning without blocking generation." | Verified | — |
| R-31 | Escalation Rules — Log Only | "Session lifecycle events, tool calls (including MCP-server tool invocations served via yaah serve), blocked commands, and file modifications are recorded to .claude/sessions/<id>.json as a durable, structured audit trail." | Partial | PRAX-2026-08-12-010 |
Findings, ordered by severity — each linked to its remit rule, evidence, and a recommended action. Tag chips jump to the relevant entry in the RAISE framework, the OWASP LLM Top 10, or the OWASP Agentic Top 10.
LLM06 primary — the finding's main OWASP categoryASI10 secondary — a category it also touches
CRITICAL PRAX-2026-08-12-001 The Notion MCP provider interpolates the operator's API token into a config value that every generator writes verbatim into repository files.
"Restricted Tools (Require Approval Before Use) / Credentials, API tokens, and OAuth secrets MUST NEVER be embedded in generated configuration files. / Credentials, API tokens, and OAuth secrets MUST NEVER be committed to the repository. / Credentials, API tokens, and OAuth secrets MUST be sourced from environment variables or a secrets manager."
- Change
Notion.Server()to emit an environment-variable reference (e.g.NOTION_TOKEN) rather than the literal value, and have the generators resolve credentials at agent start-up instead of at generation time. - Add a generator-side guard that refuses to serialize any
EnvorHeadersvalue matching a credential pattern, so a future provider cannot reintroduce the same path.
CRITICAL PRAX-2026-08-12-002 Every generated /yaah:* command, including the autonomous phase runner, is model-invocable because disable-model-invocation is never set.
"yaah MUST NEVER auto-invoke its /yaah:* workflow commands, including the autonomous workflow, without an explicit user invocation; the model must not self-trigger them."
- Set
DisableModelInvocation: trueinAutonomousCommand.Advanced()and in every other/yaah:*command whose body performs writes, so the generated frontmatter blocks model invocation. - Add a test in
pkg/commands/builtinsasserting that every registered built-in command reportsDisableModelInvocationtrue, so a new command cannot ship without it.
HIGH PRAX-2026-08-12-003 Codex-target generation silently emits a config in which neither the command guard nor the secret scanner ever runs.
"yaah MUST NEVER run with its command-guard or secret-scanner safety hooks removed, disabled, or downgraded to a non-blocking / advisory mode; these are safety controls, not optional lint."
- Map
PreToolUseandPostToolUseto their Codex equivalents inhookmap.go, or, if Codex genuinely has no equivalent event, makeCodexGenerator.GenerateHooksfail loudly when a safety-control handler cannot be wired. - Add a generator test asserting that for every target, the emitted hook set includes an event that dispatches the command guard and the secret scanner.
HIGH PRAX-2026-08-12-004 The fail-closed command guard is seven regexes over a shell, so trivial rewrites of every listed danger pass.
"A shell command matching the dangerous-command denylist (e.g. rm -rf /, force-push to a protected branch, git reset --hard, destructive SQL) MUST NEVER be allowed to execute — the command guard blocks it (fail closed)."
- Replace the free-text denylist with argv-level parsing plus an allowlist of permitted binaries and flags for the destructive verbs (
rm,git push,dd,mkfs), so unrecognised forms are denied rather than allowed. - Add table-driven tests in
pkg/hooks/handlerscovering the known bypass forms of each listed rule, so a pattern change cannot silently reopen one.
HIGH PRAX-2026-08-12-005 The secret scanner is a PostToolUse handler, so a credential-bearing edit is already on disk before the block fires.
"A file edit that introduces a hardcoded credential MUST NEVER be written — the secret scanner blocks it (fail closed)."
- Move credential detection to a
PreToolUsehandler that scans the proposedtool_inputcontent for Edit/Write/MultiEdit, keeping the PostToolUse pass as a backstop for out-of-band writes. - If the pre-write scan cannot be added, have the PostToolUse handler restore the file's prior content (or write it to a quarantine path) when it blocks, so the block is fail-closed in effect and not only in message.
HIGH PRAX-2026-08-12-006 The yaah_lint MCP tool spawns external binaries on a model-supplied path without consulting the command guard.
"No MCP tool may execute arbitrary shell commands outside the command guard, and no tool may return detected secret values in cleartext."
- Route every profile step through
CommandGuard.CheckCommandbeforeexec.CommandContext, and refuse to run when the guard reports unsafe. - Constrain
yaah_lintto paths inside the invoking project root and dropnpx-based profiles in favour of resolved local binaries, so a tool call cannot trigger a package install.
HIGH PRAX-2026-08-12-007 Default generation wires outbound MCP servers that install unpinned npm packages at every launch, with no operator opt-in.
"Only servers the operator configured / Trusted Domains / Enabling any feature that makes outbound network calls or spawns an autonomous subagent (e.g. the experimental fact-checker): such features MUST be off by default and enabled only by explicit operator opt-in."
- Pin the npm package to an exact version or digest in
context7.goandnotion.go(for example@context7/mcp@1.2.3) so the launched code matches what was reviewed. - Default
EnableContext7,EnablePulumiMCPand any future outbound provider to false inAllDefaults, requiring the same explicit opt-in the fact-check hooks already use.
MEDIUM PRAX-2026-08-12-008 MCP tool arguments reach the filesystem with no containment check, so reads and directory creation escape the declared data boundary.
"Within the target repository and the yaah cache directory / Allowed Data Sources"
- Resolve every caller-supplied path with
filepath.Absplusfilepath.Relagainst the server's project root and reject anything that escapes it, mirroringsession.sanitizeID. - Default
project_dirto the server's working directory and reject the argument entirely when it names a path outside that root.
MEDIUM PRAX-2026-08-12-009 Remote skill markdown and its third-party frontmatter are written into the host agent's context verbatim, while remote agents get theirs stripped.
- Apply
stripFrontmatterto remote skill content inRemoteSkill.resolveand rebuild the frontmatter from yaah's own metadata, matching the remote-agent path. - If remote frontmatter must be preserved, parse it and allow only a fixed key set, dropping
allowed-tools,agentandmodelunless the local catalog entry declares them.
MEDIUM PRAX-2026-08-12-010 The session audit trail never records MCP-server tool invocations and never populates its own declared Findings channel.
"Session lifecycle events, tool calls (including MCP-server tool invocations served via yaah serve), blocked commands, and file modifications are recorded to .claude/sessions/<id>.json as a durable, structured audit trail."
- Wrap the MCP tool handlers in a helper that loads the session, appends a
ToolCallRecordnaming the tool and its arguments summary, and saves — the same shapeHandleHookEventalready uses. - Populate
Session.Findingsfrom the secret-scanner and linter results so detected issues are queryable structured records rather than block-message text.
MEDIUM PRAX-2026-08-12-011 Generated settings leave every host hardening field unset even though the schema and generator fully support them.
- Populate a conservative default
Permissionsblock and anAllowedMcpServersallowlist naming exactly the providers the harness registered, inAllDefaults. - Emit
sandboxandallowManagedMcpServersOnlyas explicit defaults so the generated config states the intended posture rather than inheriting whatever the host happens to default to.
MEDIUM PRAX-2026-08-12-012 Session records capture raw Bash command text with no redaction, so credentials typed on a command line persist in the audit file.
- Run the
SecretScannerpattern set over the summarised command string insummarizeToolInputand replace any match with a location-and-pattern marker before the record is stored. - Apply the same masking to
ToolCallRecord.Reason, which currently copies the combined handler error text verbatim.
MEDIUM PRAX-2026-08-12-013 The two load-bearing safety controls have no tests of any kind, while fourteen test files cover the rest of the codebase.
- Add table-driven tests for
CommandGuard.CheckCommandandSecretScanner.ScanFilecovering each shipped pattern plus its known near-miss forms. - Wire those tests into a named CI step so a failure is attributable, rather than folded into the general
go test ./...run.
Controls and behaviors that are correctly implemented and verified during this scan. These represent areas where the agent's implementation aligns with its stated policy and security best practices.
Traversal-safe session identifiers
Every session path goes through sanitizeID, which rejects empty ids, the special values . and .., and any identifier containing a path separator or a non-base name — closing the path-traversal surface on both the CLI and the yaah_session_info MCP tool.
Immutable commit-SHA pinning across every remote source
All roughly fifty remote skill and agent references are pinned to 40-hex commit SHAs rather than branches or tags, and every GitHub Action in CI is SHA-pinned with a version comment.
Remote agent frontmatter is stripped before generation
RemoteAgent.resolve runs stripFrontmatter over fetched agent markdown, so a third-party repository cannot smuggle permissionMode, tools or other capability fields into a generated sub-agent definition.
Fail-closed hook dispatch
A handler returning Block propagates through CombineResults to ErrHookBlocked, and the hook command exits 2 — the status Claude Code and the generated OpenCode plugin both treat as a hard block.
Autonomous subagent feature is off by default
The experimental fact-check hooks, which spawn a Sonnet subagent with WebFetch, are installed only when YAAH_EXPERIMENTAL_FACT_CHECK is set in the environment, matching the remit's opt-in requirement for outbound or autonomous features.
Detected secrets are never echoed in cleartext
SecretFinding carries only file path, line number and a pattern label, and the block message reports location and pattern rather than the matched value, so neither the MCP tool response nor the session record can republish a credential.
Signed releases with an SBOM
The release pipeline runs cosign sign-blob over the artifacts and generates an SBOM with syft, both invoked from SHA-pinned actions.
Log files found in the agent's workspace during this scan. Reviewing these files provides runtime evidence to complement the static analysis above.
| Path | Source | Content Type | Purpose | Last Modified | Status |
|---|---|---|---|---|---|
| .claude/sessions/<id>.json | pkg/session/store.go via harness.HandleHookEvent | structured JSON session record | Per-session audit trail — tool calls with timestamps and input summaries, blocked calls with reasons, files modified, and a Findings array that is never populated | unknown | Inferred |
| .claude/logs/sessions.log | pkg/hooks/handlers/sessionlog.go | plaintext append-only lines | Session lifecycle only — one line per SessionStart, SessionEnd and Stop event with timestamp, event name, session id and cwd | unknown | Inferred |
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Each card represents one category and shows the top 3 findings. All items in the Findings section.
Overall maturity assessment across the six categories of the RAISE framework. This is a maturity model, not a school grade: a score of 3 / 5 means Established, not 60 percent. Most production AI agents today score between Ad hoc (1) and Established (3). See the full RAISE framework reference for the complete scale and scoring.
Maturity Scoring Rubric
Every score above is based on this scale. A score is a snapshot of observable posture — not a verdict on the people or team behind the system.
| Score | Label | Meaning |
|---|---|---|
| 5 | Exemplary | Best-in-class; automated, continuously tested, reference quality. Rarely achieved in shipping systems. |
| 4 | Strong | Comprehensive controls, active management, minor gaps. Production-ready. |
| 3 | Established | Documented controls consistently applied; known gaps accepted. A respectable baseline. |
| 2 | Partial | Some controls exist but coverage is incomplete; key gaps remain. |
| 1 | Ad hoc | Informal or inconsistent measures; relies on individual judgment. |
| 0 | Absent | No evidence this category is addressed at all. |