@sema-agent/server 1.196.0 → 1.198.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/config.js +10 -1
  3. package/dist/config.js.map +1 -1
  4. package/dist/http/server.js +1 -0
  5. package/dist/http/server.js.map +1 -1
  6. package/dist/main.js +24 -5
  7. package/dist/main.js.map +1 -1
  8. package/dist/plugins/remote-scratchpad.d.ts +8 -0
  9. package/dist/plugins/remote-scratchpad.d.ts.map +1 -0
  10. package/dist/plugins/remote-scratchpad.js +56 -0
  11. package/dist/plugins/remote-scratchpad.js.map +1 -0
  12. package/dist/task-cwd.d.ts +8 -0
  13. package/dist/task-cwd.d.ts.map +1 -1
  14. package/dist/task-cwd.js +14 -0
  15. package/dist/task-cwd.js.map +1 -1
  16. package/package.json +2 -1
  17. package/skills/code-review.md +28 -0
  18. package/skills/commit-push-pr.md +77 -0
  19. package/skills/dataviz/SKILL.md +112 -0
  20. package/skills/dataviz/references/anti-patterns.md +119 -0
  21. package/skills/dataviz/references/choosing-a-form.md +57 -0
  22. package/skills/dataviz/references/color-formula.md +113 -0
  23. package/skills/dataviz/references/components.md +39 -0
  24. package/skills/dataviz/references/interaction.md +60 -0
  25. package/skills/dataviz/references/marks-and-anatomy.md +97 -0
  26. package/skills/dataviz/references/palette.md +149 -0
  27. package/skills/dataviz/scripts/validate_palette.js +262 -0
  28. package/skills/find-skills.md +148 -0
  29. package/skills/init.md +28 -0
  30. package/skills/keybindings-help.md +294 -0
  31. package/skills/loop.md +50 -0
  32. package/skills/run-skill-generator.md +493 -0
  33. package/skills/run.md +148 -0
  34. package/skills/schedule.md +48 -0
  35. package/skills/security-review.md +181 -0
  36. package/skills/simplify.md +64 -0
  37. package/skills/update-config.md +93 -0
  38. package/skills/verify.md +334 -0
@@ -0,0 +1,181 @@
1
+ ---
2
+ name: security-review
3
+ description: Complete a security review of the pending changes on the current branch — high-confidence, exploitable findings only, with severity, exploit scenario, and fix recommendation.
4
+ ---
5
+
6
+ You are a senior security engineer conducting a focused security review of the changes on this branch.
7
+
8
+ ## Gather the change set
9
+
10
+ Run these and read the output before analyzing:
11
+
12
+ ```bash
13
+ git status
14
+ git diff --name-only origin/HEAD... # files modified
15
+ git log --no-decorate origin/HEAD... # commits
16
+ git diff origin/HEAD... # the full diff under review
17
+ ```
18
+
19
+ (No upstream/origin? Use `main...HEAD` or `HEAD~1`, and include
20
+ `git diff HEAD` if there are uncommitted changes.) The diff is the
21
+ complete review scope.
22
+
23
+ OBJECTIVE:
24
+ Perform a security-focused code review to identify HIGH-CONFIDENCE security vulnerabilities that could have real exploitation potential. This is not a general code review - focus ONLY on security implications newly added by this change set. Do not comment on existing security concerns.
25
+
26
+ CRITICAL INSTRUCTIONS:
27
+ 1. MINIMIZE FALSE POSITIVES: Only flag issues where you're >80% confident of actual exploitability
28
+ 2. AVOID NOISE: Skip theoretical issues, style concerns, or low-impact findings
29
+ 3. FOCUS ON IMPACT: Prioritize vulnerabilities that could lead to unauthorized access, data breaches, or system compromise
30
+ 4. EXCLUSIONS: Do NOT report the following issue types:
31
+ - Denial of Service (DOS) vulnerabilities, even if they allow service disruption
32
+ - Secrets or sensitive data stored on disk (these are handled by other processes)
33
+ - Rate limiting or resource exhaustion issues
34
+
35
+ SECURITY CATEGORIES TO EXAMINE:
36
+
37
+ **Input Validation Vulnerabilities:**
38
+ - SQL injection via unsanitized user input
39
+ - Command injection in system calls or subprocesses
40
+ - XXE injection in XML parsing
41
+ - Template injection in templating engines
42
+ - NoSQL injection in database queries
43
+ - Path traversal in file operations
44
+
45
+ **Authentication & Authorization Issues:**
46
+ - Authentication bypass logic
47
+ - Privilege escalation paths
48
+ - Session management flaws
49
+ - JWT token vulnerabilities
50
+ - Authorization logic bypasses
51
+
52
+ **Crypto & Secrets Management:**
53
+ - Hardcoded API keys, passwords, or tokens
54
+ - Weak cryptographic algorithms or implementations
55
+ - Improper key storage or management
56
+ - Cryptographic randomness issues
57
+ - Certificate validation bypasses
58
+
59
+ **Injection & Code Execution:**
60
+ - Remote code execution via deserialization
61
+ - Pickle injection in Python
62
+ - YAML deserialization vulnerabilities
63
+ - Eval injection in dynamic code execution
64
+ - XSS vulnerabilities in web applications (reflected, stored, DOM-based)
65
+
66
+ **Data Exposure:**
67
+ - Sensitive data logging or storage
68
+ - PII handling violations
69
+ - API endpoint data leakage
70
+ - Debug information exposure
71
+
72
+ Additional notes:
73
+ - Even if something is only exploitable from the local network, it can still be a HIGH severity issue
74
+
75
+ ANALYSIS METHODOLOGY:
76
+
77
+ Phase 1 - Repository Context Research (use file search tools):
78
+ - Identify existing security frameworks and libraries in use
79
+ - Look for established secure coding patterns in the codebase
80
+ - Examine existing sanitization and validation patterns
81
+ - Understand the project's security model and threat model
82
+
83
+ Phase 2 - Comparative Analysis:
84
+ - Compare new code changes against existing security patterns
85
+ - Identify deviations from established secure practices
86
+ - Look for inconsistent security implementations
87
+ - Flag code that introduces new attack surfaces
88
+
89
+ Phase 3 - Vulnerability Assessment:
90
+ - Examine each modified file for security implications
91
+ - Trace data flow from user inputs to sensitive operations
92
+ - Look for privilege boundaries being crossed unsafely
93
+ - Identify injection points and unsafe deserialization
94
+
95
+ REQUIRED OUTPUT FORMAT:
96
+
97
+ You MUST output your findings in markdown. The markdown output should contain the file, line number, severity, category (e.g. `sql_injection` or `xss`), description, exploit scenario, and fix recommendation.
98
+
99
+ For example:
100
+
101
+ # Vuln 1: XSS: `foo.py:42`
102
+
103
+ * Severity: High
104
+ * Description: User input from `username` parameter is directly interpolated into HTML without escaping, allowing reflected XSS attacks
105
+ * Exploit Scenario: Attacker crafts URL like /bar?q=<script>alert(document.cookie)</script> to execute JavaScript in victim's browser, enabling session hijacking or data theft
106
+ * Recommendation: Use the framework's escaping function or templates with auto-escaping enabled for all user inputs rendered in HTML
107
+
108
+ SEVERITY GUIDELINES:
109
+ - **HIGH**: Directly exploitable vulnerabilities leading to RCE, data breach, or authentication bypass
110
+ - **MEDIUM**: Vulnerabilities requiring specific conditions but with significant impact
111
+ - **LOW**: Defense-in-depth issues or lower-impact vulnerabilities
112
+
113
+ CONFIDENCE SCORING:
114
+ - 0.9-1.0: Certain exploit path identified, tested if possible
115
+ - 0.8-0.9: Clear vulnerability pattern with known exploitation methods
116
+ - 0.7-0.8: Suspicious pattern requiring specific conditions to exploit
117
+ - Below 0.7: Don't report (too speculative)
118
+
119
+ FINAL REMINDER:
120
+ Focus on HIGH and MEDIUM findings only. Better to miss some theoretical issues than flood the report with false positives. Each finding should be something a security engineer would confidently raise in a PR review.
121
+
122
+ FALSE POSITIVE FILTERING:
123
+
124
+ > You do not need to run commands to reproduce the vulnerability, just read the code to determine if it is a real vulnerability. Do not use the shell tool or write to any files.
125
+ >
126
+ > HARD EXCLUSIONS - Automatically exclude findings matching these patterns:
127
+ > 1. Denial of Service (DOS) vulnerabilities or resource exhaustion attacks.
128
+ > 2. Secrets or credentials stored on disk if they are otherwise secured.
129
+ > 3. Rate limiting concerns or service overload scenarios.
130
+ > 4. Memory consumption or CPU exhaustion issues.
131
+ > 5. Lack of input validation on non-security-critical fields without proven security impact.
132
+ > 6. Input sanitization concerns for CI workflow files unless they are clearly triggerable via untrusted input.
133
+ > 7. A lack of hardening measures. Code is not expected to implement all security best practices, only flag concrete vulnerabilities.
134
+ > 8. Race conditions or timing attacks that are theoretical rather than practical issues. Only report a race condition if it is concretely problematic.
135
+ > 9. Vulnerabilities related to outdated third-party libraries. These are managed separately and should not be reported here.
136
+ > 10. Memory safety issues such as buffer overflows or use-after-free vulnerabilities are impossible in Rust. Do not report memory safety issues in Rust or any other memory safe languages.
137
+ > 11. Files that are only unit tests or only used as part of running tests.
138
+ > 12. Log spoofing concerns. Outputting un-sanitized user input to logs is not a vulnerability.
139
+ > 13. SSRF vulnerabilities that only control the path. SSRF is only a concern if it can control the host or protocol.
140
+ > 14. Including user-controlled content in AI system prompts is not a vulnerability.
141
+ > 15. Regex injection. Injecting untrusted content into a regex is not a vulnerability.
142
+ > 16. Regex DOS concerns.
143
+ > 17. Insecure documentation. Do not report any findings in documentation files such as markdown files.
144
+ > 18. A lack of audit logs is not a vulnerability.
145
+ >
146
+ > PRECEDENTS -
147
+ > 1. Logging high value secrets in plaintext is a vulnerability. Logging URLs is assumed to be safe.
148
+ > 2. UUIDs can be assumed to be unguessable and do not need to be validated.
149
+ > 3. Environment variables and CLI flags are trusted values. Attackers are generally not able to modify them in a secure environment. Any attack that relies on controlling an environment variable is invalid.
150
+ > 4. Resource management issues such as memory or file descriptor leaks are not valid.
151
+ > 5. Subtle or low impact web vulnerabilities such as tabnabbing, XS-Leaks, prototype pollution, and open redirects should not be reported unless they are extremely high confidence.
152
+ > 6. React and Angular are generally secure against XSS. These frameworks do not need to sanitize or escape user input unless it is using dangerouslySetInnerHTML, bypassSecurityTrustHtml, or similar methods. Do not report XSS vulnerabilities in React or Angular components or tsx files unless they are using unsafe methods.
153
+ > 7. Most vulnerabilities in CI workflow files are not exploitable in practice. Before validating a CI workflow vulnerability ensure it is concrete and has a very specific attack path.
154
+ > 8. A lack of permission checking or authentication in client-side JS/TS code is not a vulnerability. Client-side code is not trusted and does not need to implement these checks, they are handled on the server-side. The same applies to all flows that send untrusted data to the backend, the backend is responsible for validating and sanitizing all inputs.
155
+ > 9. Only include MEDIUM findings if they are obvious and concrete issues.
156
+ > 10. Most vulnerabilities in notebook files (*.ipynb) are not exploitable in practice. Before validating a notebook vulnerability ensure it is concrete and has a very specific attack path where untrusted input can trigger the vulnerability.
157
+ > 11. Logging non-PII data is not a vulnerability even if the data may be sensitive. Only report logging vulnerabilities if they expose sensitive information such as secrets, passwords, or personally identifiable information (PII).
158
+ > 12. Command injection vulnerabilities in shell scripts are generally not exploitable in practice since shell scripts generally do not run with untrusted user input. Only report command injection vulnerabilities in shell scripts if they are concrete and have a very specific attack path for untrusted input.
159
+ >
160
+ > SIGNAL QUALITY CRITERIA - For remaining findings, assess:
161
+ > 1. Is there a concrete, exploitable vulnerability with a clear attack path?
162
+ > 2. Does this represent a real security risk vs theoretical best practice?
163
+ > 3. Are there specific code locations and reproduction steps?
164
+ > 4. Would this finding be actionable for a security team?
165
+ >
166
+ > For each finding, assign a confidence score from 1-10:
167
+ > - 1-3: Low confidence, likely false positive or noise
168
+ > - 4-6: Medium confidence, needs investigation
169
+ > - 7-10: High confidence, likely true vulnerability
170
+
171
+ START ANALYSIS:
172
+
173
+ Begin your analysis now. Do this in 3 steps:
174
+
175
+ 1. Use a subagent (e.g. the Task tool) to identify vulnerabilities. It should use the repository exploration tools to understand the codebase context, then analyze the changes for security implications. In the prompt for this subagent, include all of the above.
176
+ 2. Then for each vulnerability identified by the above subagent, create a new subagent to filter out false-positives. Launch these subagents in parallel. In the prompt for these subagents, include everything in the "FALSE POSITIVE FILTERING" instructions.
177
+ 3. Filter out any vulnerabilities where the subagent reported a confidence less than 8.
178
+
179
+ If subagents are unavailable in this session, do the same three passes yourself, strictly separating the find pass from the false-positive filtering pass.
180
+
181
+ Your final reply must contain the markdown report and nothing else.
@@ -0,0 +1,64 @@
1
+ ---
2
+ name: simplify
3
+ description: Review the changed code for reuse, simplification, efficiency, and altitude cleanups, then apply the fixes. Quality only — it does not hunt for bugs; use a code-review pass for that.
4
+ ---
5
+
6
+ You are improving the quality of the changed code, not hunting for bugs. Review
7
+ it for reuse, simplification, efficiency, and altitude issues, then fix what you
8
+ find. Do not look for correctness bugs — that is what a code-review pass is for.
9
+
10
+ ## Phase 0 — Gather the diff
11
+
12
+ Run `git diff @{upstream}...HEAD` (or `git diff main...HEAD` / `git diff HEAD~1`
13
+ if there's no upstream) to get the unified diff under review. If there are
14
+ uncommitted changes, or the range diff is empty, also run `git diff HEAD` and
15
+ include the working-tree changes in scope — the review often runs before the
16
+ commit. If a branch name or file path was given as the target, review that
17
+ target instead. Treat this diff as the review scope.
18
+
19
+ ## Phase 1 — Review (4 cleanup agents in parallel)
20
+
21
+ Launch **4 independent review agents** via your subagent tool (e.g. Task), all
22
+ in a single message so they run concurrently. Pass each agent the diff and one
23
+ of the four angles below. Each returns its findings with `file`, `line`, a
24
+ one-line `summary`, and the concrete cost (what is duplicated, wasted, or
25
+ harder to maintain). If subagents are unavailable in this session, work the
26
+ four angles yourself, one at a time.
27
+
28
+ ### Reuse
29
+
30
+ Flag new code that re-implements something the codebase
31
+ already has — grep shared/utility modules and files adjacent to the change,
32
+ and name the existing helper to call instead.
33
+
34
+ ### Simplification
35
+
36
+ Flag unnecessary complexity the diff adds: redundant or derivable state,
37
+ copy-paste with slight variation, deep nesting, dead code left behind. Name
38
+ the simpler form that does the same job.
39
+
40
+ ### Efficiency
41
+
42
+ Flag wasted work the diff introduces: redundant computation or repeated I/O,
43
+ independent operations run sequentially, blocking work added to startup or
44
+ hot paths. Also flag long-lived objects built from closures or captured
45
+ environments — they keep the entire enclosing scope alive for the object's
46
+ lifetime (a memory leak when that scope holds large values); prefer a
47
+ class/struct that copies only the fields it needs. Name the cheaper
48
+ alternative.
49
+
50
+ ### Altitude
51
+
52
+ Check that each change is implemented at the right depth, not as a fragile
53
+ bandaid. Special cases layered on shared infrastructure are a sign the fix
54
+ isn't deep enough — prefer generalizing the underlying mechanism over adding
55
+ special cases.
56
+
57
+ ## Phase 2 — Apply the fixes
58
+
59
+ Wait for all four agents to complete, dedup findings that point at the same
60
+ line or mechanism, and fix each remaining one directly. Skip any finding whose
61
+ fix would change intended behavior, require changes well outside the reviewed
62
+ diff, or that you judge to be a false positive — note the skip rather than
63
+ arguing with it. Finish with a brief summary of what was fixed and what was
64
+ skipped (or confirm the code was already clean).
@@ -0,0 +1,93 @@
1
+ ---
2
+ name: update-config
3
+ description: Use this skill to configure sema via its settings files. Automated behaviors ("from now on when X", "each time X", "whenever X", "before/after X") require hooks configured in settings files - the harness executes these, not the model, so memory/preferences cannot fulfill them. Also use for permissions ("allow X", "add permission", "move permission to"), env vars ("set X=Y"), model catalog changes (config.d/models.json), hook troubleshooting, or any changes to settings.json/settings.local.json files.
4
+ ---
5
+
6
+ # Updating sema configuration
7
+
8
+ sema is configured through layered JSON settings files plus a model catalog. This skill covers where each file lives, which layer wins, what the schema accepts, and the safety rules the resolver enforces.
9
+
10
+ ## Config home directory
11
+
12
+ All user-level configuration lives under the sema config home, resolved in this priority order:
13
+
14
+ 1. `SEMA_CONFIG_DIR` env var (explicit override)
15
+ 2. `CLAUDE_CONFIG_DIR` env var (upstream-CLI compatibility fallback)
16
+ 3. `~/.sema` — the default. sema does NOT silently read `~/.claude`; users migrating from the upstream CLI import explicitly with `sema config sync` (idempotent; `--project`, `--merge`, `--overwrite`, `--dry-run` supported). Setting `SEMA_CLAUDE_FALLBACK=1` opts back in to automatic `~/.claude` reads.
17
+
18
+ Below, `<config-home>` means the directory resolved above.
19
+
20
+ ## Settings file locations and precedence
21
+
22
+ Choose the file by scope. Later layers override earlier ones on value conflicts:
23
+
24
+ | Precedence | Layer | File | Git | Use for |
25
+ |---|---|---|---|---|
26
+ | 1 (lowest) | userSettings | `<config-home>/settings.json` | N/A | Personal preferences for all projects |
27
+ | 2 | projectSettings | `<project>/.claude/settings.json` | Commit | Team-wide hooks, permissions, env |
28
+ | 3 | localSettings | `<project>/.claude/settings.local.json` | Gitignore | Personal overrides for this project |
29
+ | 4 | flagSettings | `--settings <file>` CLI flag | N/A | One-shot launch overrides |
30
+ | 5 (highest) | policySettings | `managed-settings.json` + `managed-settings.d/*.json` (admin-owned), or remote managed settings | N/A | Managed/MDM policy ceiling |
31
+
32
+ Project-scoped files intentionally keep the `.claude/` directory name for upstream ecosystem compatibility.
33
+
34
+ ## Trust model (independent of precedence)
35
+
36
+ sema separates "whose value wins" (precedence above) from "who is allowed to set a key" (trust). Trust per layer: userSettings = `global`, projectSettings = `project`, localSettings and `--settings` flag = `local`, policySettings = `managed`. The resolver fails CLOSED with an error (never silently applies) when:
37
+
38
+ - **SettingsTrustViolation** — a layer sets a key above its trust ceiling (e.g. a committed project file trying to set a global-trust security key).
39
+ - **OverrideLockViolation** — a tighten-only key would be LOOSENED by a later layer. Permission denies fold deny-first: a later `allow` can never widen back a capability an earlier layer denied.
40
+ - `permissionMode: "bypassPermissions"` in ANY settings file is rejected outright — bypass is a launch-flag-only mode, never file-configurable.
41
+ - `disableBypassPermissionsMode` and `disableAutoMode` are managed-only kill switches: only the policy layer may set them, and `true` (the strict pole) cannot be relaxed by lower layers.
42
+
43
+ When an edit you made produces one of these errors, move the key to a sufficiently trusted file instead of fighting the resolver.
44
+
45
+ ## Settings schema
46
+
47
+ The core resolved units (`SemaSettings`):
48
+
49
+ ```json
50
+ {
51
+ "permissions": {
52
+ "allow": ["Bash(npm:*)", "Read"],
53
+ "deny": ["Bash(rm -rf:*)"],
54
+ "ask": ["Write(/etc/*)"],
55
+ "defaultMode": "default" | "acceptEdits" | "plan",
56
+ "additionalDirectories": ["/extra/dir"],
57
+ "disableBypassPermissionsMode": true,
58
+ "disableAutoMode": true
59
+ },
60
+ "hooks": {
61
+ "PreToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command", "command": "./check.sh", "timeout": 30 }] }],
62
+ "PostToolUse": [],
63
+ "UserPromptSubmit": []
64
+ },
65
+ "env": { "DEBUG": "true" },
66
+ "model": "model-name",
67
+ "outputStyle": "style-name",
68
+ "webSearch": { "provider": "brave" | "tavily" | "searxng", "apiKey": "...", "endpoint": "...", "maxResults": 5 },
69
+ "ultracode": true
70
+ }
71
+ ```
72
+
73
+ Notes:
74
+
75
+ - **Permission rule syntax** is upstream-compatible: exact match `"Bash(npm run test)"`, prefix wildcard `"Bash(git:*)"`, tool-only `"Read"`.
76
+ - `webSearch` and `ultracode` are sema-only keys (no upstream equivalent).
77
+ - Settings files accept the wider upstream settings.json superset; unknown keys are tolerated, but the units above are what the sema resolver folds across layers.
78
+
79
+ ## Model configuration (sema-specific)
80
+
81
+ Models are NOT configured via a bare `"model": "sonnet"` alias. Two channels, both under the user layer:
82
+
83
+ 1. **Model catalog** — `<config-home>/config.d/models.json`: a multi-slot catalog of entries `{ name, id, api, baseUrl, apiKeyEnv, contextWindow, maxTokens }` where `api` is `"anthropic-messages"` or `"openai-completions"`. A catalog with enabled models REPLACES the env catalog, and the FIRST enabled entry is the default model. Secrets never go in this file: `apiKeyEnv` names an env var (convention `SEMA_MODEL_KEY_<ENTRY>`) whose value lives in the userSettings `env` block.
84
+ 2. **Env two-slot fallback** — when no catalog exists, the settings `env` block drives models directly: `MODEL_ID` (main), `MODEL_CHEAP_ID` (cheap/summarize slot), `MODEL_API_KEY` (or `ANTHROPIC_AUTH_TOKEN`), `ANTHROPIC_BASE_URL` (anthropic-messages routes) or `MODEL_GATEWAY_BASEURL` (openai-completions routes), plus optional `MODEL_CONTEXT_WINDOW` / `MODEL_MAX_TOKENS`.
85
+
86
+ Prefer editing the catalog when it exists; only touch the env slots for catalog-less installs.
87
+
88
+ ## How to apply a change
89
+
90
+ 1. Pick the narrowest file that satisfies the scope and trust rules above.
91
+ 2. Read the existing file first; merge your key in — never clobber unrelated keys.
92
+ 3. Settings files are watched: edits hot-reload without a restart. If a change appears ignored, check for a resolver rejection (trust/tighten violation) before assuming a bug.
93
+ 4. For "do X automatically every time Y" requests, configure a hook — do not promise behavior from memory.
@@ -0,0 +1,334 @@
1
+ ---
2
+ name: verify
3
+ description: Verify that a code change actually does what it's supposed to by exercising it end-to-end and observing behavior — drive the affected flow, not just tests or typecheck. Run before committing nontrivial changes. Don't invoke it on a diff that only touches tests, docs, or other code with no runtime surface to drive (a change to product source always has one) — there's nothing to observe.
4
+ ---
5
+
6
+ **Verification is runtime observation.** You build the app, run it,
7
+ drive it to where the changed code executes, and capture what you
8
+ see. That capture is your evidence. Nothing else is.
9
+
10
+ **Don't run tests. Don't typecheck.** Running them here proves you
11
+ can run CI — not that the change works. Not as a warm-up,
12
+ not "just to be sure," not as a regression sweep after. The time
13
+ goes to running the app instead.
14
+
15
+ **Don't import-and-call.** `import { foo } from './src/...'` then
16
+ `console.log(foo(x))` is a unit test you wrote. The function did what
17
+ the function does — you knew that from reading it. The app never ran.
18
+ Whatever calls `foo` in the real codebase ends at a CLI, a socket, or
19
+ a window. Go there.
20
+
21
+ ## Find the change
22
+
23
+ The scope is what you're verifying — usually a diff, sometimes just
24
+ "does X work." In a git repo, establish the full range (a branch may
25
+ be many commits, or the change may still be uncommitted):
26
+
27
+ ```bash
28
+ git log --oneline @{u}.. # count commits (if upstream set)
29
+ git diff @{u}.. --stat # full range, not HEAD~1
30
+ git diff origin/HEAD... --stat # no upstream: committed vs base
31
+ git diff HEAD --stat # uncommitted: working tree vs HEAD
32
+ ```
33
+
34
+ State the commit count. Large diff truncating? Redirect to a file
35
+ then read it. Repo but no diff from any of these → say so, stop.
36
+ **No repo → the scope is whatever the user named; ask if they
37
+ didn't.**
38
+
39
+ **The diff is ground truth. Any description is a claim about it.**
40
+ Read both. If they disagree, that's a finding.
41
+
42
+ ## Surface
43
+
44
+ The surface is where a user — human or programmatic — meets the
45
+ change. That's where you observe.
46
+
47
+ | Change reaches | Surface | You |
48
+ |---|---|---|
49
+ | CLI / TUI | terminal | type the command, capture the pane — see the CLI example below |
50
+ | Server / API | socket | send the request, capture the response — see the server example below |
51
+ | GUI | pixels | drive it headless (xvfb / a browser driver), screenshot |
52
+ | Library | package boundary | sample code through the public export — `import pkg`, not `import ./src/...` |
53
+ | Prompt / agent config | the agent | run the agent, capture its behavior |
54
+ | CI workflow | the CI system | dispatch it, read the run |
55
+
56
+ **Internal function? Not a surface.** Something in the repo calls it
57
+ and that caller ends at one of the rows above. Follow it there. A
58
+ shell security gate's surface isn't the function's return value — it's
59
+ the CLI prompting or auto-allowing when you type the command.
60
+
61
+ **No runtime surface at all** — docs-only, type declarations with no
62
+ emit, build config that produces no behavioral diff — report
63
+ **SKIP — no runtime surface: (reason).** Don't run tests to fill
64
+ the space.
65
+
66
+ **Tests in the diff are the author's evidence, not a surface.** CI
67
+ runs them. You'd be re-running CI. Tests-only change → SKIP, one line.
68
+ Mixed src+tests → verify the src, ignore the test files. Reading a
69
+ test to learn what to check is fine — it's a spec. But then go run
70
+ the app. Checking that assertions match source is code review.
71
+
72
+ ## Get a handle
73
+
74
+ **Check your available skills first — even if you already know how to
75
+ build and run.** A skill that matches your surface (a verifier or
76
+ run recipe for this kind of app) is a verified path: follow its
77
+ setup. A stale recipe (fails on mechanics unrelated to the change)
78
+ → note it; don't FAIL the change for recipe rot. Also check the
79
+ repo's own entry points: README, package.json scripts, Makefile,
80
+ docs.
81
+
82
+ - **A matching launch/verify recipe exists** → use its build/launch
83
+ primitives as your handle.
84
+ - **Nothing** → cold start from README/package.json/Makefile. Timebox
85
+ ~15min. Stuck → BLOCKED with exactly where it stopped. Got
86
+ through → **persist what you learned** in your report: the exact
87
+ build/launch/drive commands that worked, the flows worth driving,
88
+ any gotchas — so the recipe can be captured as a project skill and
89
+ the next session skips this cold start.
90
+
91
+ ## Drive it
92
+
93
+ Smallest path that makes the changed code execute:
94
+
95
+ - Changed a flag? Run with it.
96
+ - Changed a handler? Hit that route.
97
+ - Changed error handling? Trigger the error.
98
+ - Changed an internal function? Find the CLI command / request / render
99
+ that reaches it. Run that.
100
+
101
+ **Read your plan back before running.** If every step is build /
102
+ typecheck / run test file — you've planned a CI rerun, not a
103
+ verification. Find a step that reaches the surface or report BLOCKED.
104
+
105
+ **The verdict is table stakes. Your observations are the signal.**
106
+ A PASS with three sharp "hey, I noticed…" lines is worth more than a
107
+ bare PASS. You're the only reviewer who actually *ran* the thing —
108
+ anything that made you pause, work around, or go "huh" is information
109
+ the author doesn't have. Don't filter for "is this a bug." Filter for
110
+ "would I mention this if they were sitting next to me."
111
+
112
+ **End-to-end, through the real interface.** Pieces passing in
113
+ isolation doesn't mean the flow works — seams are where bugs hide.
114
+ If users click buttons, test by clicking buttons, not by curling the
115
+ API underneath.
116
+
117
+ **Destructive path?** If the change touches code that deletes,
118
+ publishes, sends, or writes outside the workspace and there's no
119
+ dry-run or safe target, don't drive it live. Verify what you can
120
+ around it and say which path you didn't exercise and why.
121
+
122
+ ## Push on it
123
+
124
+ The claim checked out — that's the first half. Confirming is step
125
+ one, not the job. The description is what the author intended;
126
+ your value is what they didn't.
127
+
128
+ You know exactly what changed. Probe *around* it, at the same
129
+ surface you just drove:
130
+
131
+ - **New flag / option** → empty value, passed twice, combined with a
132
+ conflicting flag, typo'd (does the error name it?)
133
+ - **New handler / route** → wrong method, malformed body, missing
134
+ required field, oversized payload
135
+ - **Changed error path** → the adjacent errors it didn't touch —
136
+ did the refactor catch them too, or only the one in the diff?
137
+ - **Interactive / TUI** → Ctrl-C mid-op, resize the pane, paste
138
+ garbage, rapid-fire the key, Esc at the wrong moment
139
+ - **State / persistence** → do it twice, do it with stale state
140
+ underneath, do it in two sessions at once
141
+ - **Wander** → what's adjacent? What looked off while you were
142
+ confirming? Go back to it.
143
+
144
+ These aren't a checklist — pick the ones the change points at. Stop
145
+ when you've covered the obvious adjacents or hit something worth a
146
+ ⚠️. A probe that finds nothing is still a step: "🔍 passed `--from ''`
147
+ → clean `error: --from requires a value`, exit 2." That the author
148
+ didn't test it is exactly why it's worth knowing it holds.
149
+
150
+ Still not a test run. You're at the surface, typing what a user
151
+ would type wrong.
152
+
153
+ ## Capture
154
+
155
+ Stdout, response bodies, screenshots, pane dumps. Captured output is
156
+ evidence; your memory isn't. Something unexpected? Don't route around
157
+ it — capture, note, decide if it's the change or the environment.
158
+ Unrelated breakage is a finding, not noise.
159
+
160
+ Shared process state (tmux, ports, lockfiles) — isolate. `tmux -L
161
+ name`, bind `:0`, `mktemp -d`. You share a namespace with your host.
162
+
163
+ ## Report
164
+
165
+ Inline, final message:
166
+
167
+ ```
168
+ ## Verification: <one-line what changed>
169
+
170
+ **Verdict:** PASS | FAIL | BLOCKED | SKIP
171
+
172
+ **Claim:** <what it's supposed to do — your read of the diff and/or
173
+ the stated claim; note any mismatch>
174
+
175
+ **Method:** <how you got a handle — which recipe/skill, or cold
176
+ start; what you launched>
177
+
178
+ ### Steps
179
+
180
+ Each step is one thing you did to the **running app** and what it
181
+ showed. Build/install/checkout are setup, not steps. Test runs and
182
+ typecheck don't belong here — they're CI's output.
183
+
184
+ 1. ✅/❌/⚠️/🔍 <what you did to the running app> → <what you observed>
185
+ <evidence: the app's own output — pane capture, response body,
186
+ screenshot>
187
+
188
+ 🔍 marks a probe — a step off the claim's happy path, trying to
189
+ break it. At least one. A Steps list that's all ✅ and no 🔍 is a
190
+ happy-path replay: still PASS, but you stopped at the first half.
191
+
192
+ **Screenshot / sample:** <the one frame a reviewer looks at to see
193
+ the feature — an image for GUI/TUI, code block for library/API;
194
+ omit for build/types-only>
195
+
196
+ ### Findings
197
+ <Things you noticed. Not just bugs — friction, surprises, anything
198
+ a first-time user would trip on. "Took three tries to find the right
199
+ flag." "Error message on typo was unhelpful." "Default seems odd for
200
+ the common case." "Works, but slower than I expected." Lower the bar:
201
+ if it made you pause, it goes here. But the pause has to be yours,
202
+ from running the app — not from reading the change description. A red
203
+ CI check, a review comment, someone else's bot: visible to anyone
204
+ already, and you relaying it isn't an observation. Claim/diff
205
+ mismatch, pre-existing breakage, and env notes also belong.
206
+
207
+ Each probe gets a line here even when it held — "🔍 empty `--from`
208
+ → clean error" tells the author what *was* covered, which they
209
+ can't see from a bare PASS.
210
+
211
+ Lead with ⚠️ for lines worth interrupting the reviewer for; plain
212
+ bullets are context. Empty is fine if nothing stuck out — but nothing
213
+ sticking out is itself rare.>
214
+ ```
215
+
216
+ **Evidence has to reach the reader.** A file path is only evidence
217
+ if the person reading the report can open it. If the `SendUserFile`
218
+ tool is in your toolset, you're on a remote surface where they
219
+ can't — send the screenshots and recordings with it and let the
220
+ report name what you sent. Without it, reference the path and keep
221
+ the evidence that matters inline — pane captures and response
222
+ bodies travel in the report; a bare path only works when the reader
223
+ shares your filesystem.
224
+
225
+ **Verdicts:**
226
+ - **PASS** — you ran the app, the change did what it should at its
227
+ surface. Not: tests pass, builds clean, code looks right.
228
+ - **FAIL** — you ran it and it doesn't. Or it breaks something else.
229
+ Or claim and diff disagree materially.
230
+ - **BLOCKED** — couldn't reach a state where the change is observable.
231
+ Build broke, env missing a dep, handle wouldn't come up. Not a
232
+ verdict on the change. Never report an approach blocked or
233
+ impossible until you've checked the skills and recipes available
234
+ to you — environment-specific unlocks (headless runners, login
235
+ helpers, VM harnesses) usually live there. Say exactly where it
236
+ stopped.
237
+ - **SKIP** — no runtime surface exists. Docs-only, types-only,
238
+ tests-only. Nothing went wrong; there's just nothing here to run.
239
+ One line why.
240
+
241
+ No partial pass. "3 of 4 passed" is FAIL until 4 passes or is
242
+ explained away.
243
+
244
+ **When in doubt, FAIL.** False PASS ships broken code; false FAIL
245
+ costs one more human look. Ambiguous output is FAIL with the raw
246
+ capture attached — don't interpret.
247
+
248
+ ## Appendix: verifying a CLI change
249
+
250
+ The handle is direct invocation. The evidence is stdout/stderr/exit code.
251
+
252
+ 1. Build (if the CLI needs building)
253
+ 2. Run with arguments that exercise the changed code
254
+ 3. Capture output and exit code
255
+ 4. Compare to expected
256
+
257
+ Worked example — **diff:** adds a `--json` flag to the `status`
258
+ subcommand. **Claim:** "machine-readable status output."
259
+ **Inference:** `tool status --json` now exists, emits valid JSON with
260
+ the same fields the human output shows; `tool status` without the
261
+ flag is unchanged.
262
+
263
+ ```bash
264
+ go build -o /tmp/tool ./cmd/tool
265
+
266
+ /tmp/tool status
267
+ # → Status: healthy / Uptime: 3h12m / Connections: 47
268
+
269
+ /tmp/tool status --json
270
+ # → {"status":"healthy","uptime_seconds":11520,"connections":47}
271
+
272
+ /tmp/tool status --json | jq -e .status
273
+ # → "healthy" (jq -e exits nonzero if the path is null/false)
274
+ echo $?
275
+ # → 0
276
+ ```
277
+
278
+ **Verdict:** PASS — flag works, JSON is valid, fields line up.
279
+
280
+ What FAIL looks like: `unknown flag: --json` → not wired up, or a
281
+ stale build; output isn't valid JSON → serialization bug; `tool
282
+ status` (no flag) changed → regression; JSON field names differ from
283
+ expected → claim/code mismatch, note it.
284
+
285
+ If the CLI reads stdin → pipe in test data. If it writes files / hits
286
+ a network / deletes things → point it at a tmp dir / a mock / a
287
+ dry-run flag. No safe mode and the diff touches the destructive
288
+ path → say so and verify what you can around it.
289
+
290
+ ## Appendix: verifying a server/API change
291
+
292
+ The handle is `curl` (or equivalent). The evidence is the response.
293
+
294
+ 1. Start the server (background, with a readiness poll)
295
+ 2. `curl` the route the diff touches, with inputs that hit the changed branch
296
+ 3. Capture the full response (status + headers + body)
297
+ 4. Compare to expected
298
+
299
+ Lifecycle, when no launch recipe exists:
300
+
301
+ ```bash
302
+ <start-command> &> /tmp/server.log &
303
+ SERVER_PID=$!
304
+ for i in {1..30}; do curl -sf localhost:PORT/health >/dev/null && break; sleep 1; done
305
+ # ... your curls ...
306
+ kill $SERVER_PID
307
+ ```
308
+
309
+ No readiness endpoint? Poll the route you're about to test until it
310
+ stops returning connection-refused, then add a beat.
311
+
312
+ Worked example — **diff:** adds a `Retry-After` header to 429
313
+ responses in `rateLimit.ts`. **Claim:** "clients can now back off
314
+ correctly." **Inference:** hitting the rate limit should now return
315
+ `Retry-After: <n>` in the response headers; it didn't before.
316
+
317
+ ```bash
318
+ # trigger the limit — 10 fast requests, limit is 5/sec per the diff
319
+ for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" localhost:3000/api/thing; done
320
+ # → 200 200 200 200 200 429 429 429 429 429
321
+
322
+ # capture the 429 headers
323
+ curl -si localhost:3000/api/thing | head -20
324
+ # → HTTP/1.1 429 Too Many Requests
325
+ # → Retry-After: 12
326
+ ```
327
+
328
+ **Verdict:** PASS — `Retry-After: 12` present, positive integer.
329
+
330
+ What FAIL looks like: header absent → the diff didn't take effect, or
331
+ you're not actually hitting the 429 path (check the status code
332
+ first); header present but `NaN` / `undefined` / negative → the logic
333
+ is wrong; 200s all the way through → you never triggered the changed
334
+ path — tighten the burst or check the limit config.