ask-claude v2.6.1, ask-hermes v4.2.0, ask-dev v1.1.0, create-plan v1.1.0
- ask-claude v2.4.0 -> v2.6.1: Added mandatory disagreement scan (Step 3.5) with web-reference demand + internal consistency check. Updated callouts for the paste-vs-path rule (now HARD RULE, not just example). - ask-hermes v4.1.1 -> v4.2.0: Added mandatory disagreement scan mirroring ask-claude. - ask-dev v1.0.0 -> v1.1.0: Added mandatory disagreement scan mirroring ask-claude. - create-plan v1.1.0 (new): Multi-agent plan-build dispatcher. Trigger phrases, 10-Q brief script (min as needed, max 10), curator dispatch, capture/handoff format, all 6 failure modes. Companion references: curator-framing-prompt.md, deep-research-dispatch-template.md, ask-claude-validation-template.md, structured-brief-10q.md. 5 rounds of Claude validation on the design plan; final SHIP from ask-hermes peer review.
This commit is contained in:
151
ask-claude/references/ask-claude-payload-pattern.md
Normal file
151
ask-claude/references/ask-claude-payload-pattern.md
Normal file
@@ -0,0 +1,151 @@
|
||||
# Ask-Claude Payload Pattern
|
||||
|
||||
Session-specific detail for the `ask-claude` skill: how to send questions to Claude
|
||||
Opus 4.8 on 10.0.0.28 reliably, capture the session_id, handle shell metacharacters,
|
||||
and avoid the filename-collision gotcha that bites when `read_file` returns a
|
||||
different schema than expected.
|
||||
|
||||
## Pattern: scp + ask.sh
|
||||
|
||||
The `ask.sh` wrapper on 10.0.0.28 handles mktemp snapshot, claude invocation
|
||||
(`--output-format json --model claude-opus-4-8 --max-turns 30`, `timeout 280`, `|| true`),
|
||||
fetches the usage API, and runs `merge.py` to produce a single JSON envelope.
|
||||
|
||||
**Why scp, not heredoc:** shell metacharacters (`"`, `$`, `(`, `)`, backticks) in
|
||||
the question content will break heredoc-based writes. For ANY non-trivial question
|
||||
write the question to a local temp file, scp it, and pass the remote path to
|
||||
`ask.sh --qfile`.
|
||||
|
||||
```bash
|
||||
# 1. Write question locally
|
||||
write_file("/tmp/ask-claude-q.txt", content=question)
|
||||
|
||||
# 2. Copy to remote
|
||||
terminal("scp /tmp/ask-claude-q.txt n8n@10.0.0.28:/tmp/ask-claude-q.txt")
|
||||
|
||||
# 3. Run via ask.sh
|
||||
terminal("ssh n8n@10.0.0.28 '~/claude/hermes_support/ask.sh --qfile /tmp/ask-claude-q.txt'")
|
||||
```
|
||||
|
||||
## JSON envelope fields
|
||||
|
||||
Always parse these from the `--output-format json` response:
|
||||
|
||||
| Field | When | Use |
|
||||
|---|---|---|
|
||||
| `session_id` | Always (including errors) | Capture for `--resume` follow-ups |
|
||||
| `result` | Success | The answer text |
|
||||
| `is_error` | Always | `true` if anything failed |
|
||||
| `subtype` | Always | `success` / `error_max_turns` / `error_budget` |
|
||||
| `total_cost_usd` | Always | Track spend |
|
||||
| `num_turns` | Always | How many agentic loops |
|
||||
| `usage.input_tokens` | Always | Context usage |
|
||||
| `usage.cache_creation_input_tokens` | Always | Context usage |
|
||||
| `usage.cache_read_input_tokens` | Always | Context usage |
|
||||
| `output_tokens` | Always | Context usage |
|
||||
| `modelUsage.{model}.contextWindow` | Always | Context window size — iterate keys, don't hardcode |
|
||||
| `stop_reason` | Always | Why Claude stopped |
|
||||
|
||||
**Critical: capture `session_id` from EVERY response, including errors.** A turn can
|
||||
error yet still advance the session. If you only store it on success, `--resume` breaks.
|
||||
|
||||
**Critical: detect `error_max_turns` via `subtype`, not `is_error`.** `error_max_turns`
|
||||
has `is_error: false` but no `result` field. Empty-answer detection requires checking
|
||||
`subtype == 'error_max_turns'`.
|
||||
|
||||
## Asking Claude to validate a file
|
||||
|
||||
Claude (Opus on 10.0.0.28) has **no filesystem access to the operator's machine**.
|
||||
When asking Claude to validate a plan, code, or doc:
|
||||
|
||||
1. **Read the file locally** with `read_file` or `terminal cat > /tmp/file.txt`
|
||||
2. **Inline the content in the question** as a fenced block
|
||||
3. **Tell Claude explicitly** the file is pasted inline (not a path to read)
|
||||
|
||||
**Common failure mode:** pasting a path like `/home/n8n/workspace/...` and asking
|
||||
Claude to validate it. Claude will reply "I can't read that file" and refuse to
|
||||
validate. Always inline.
|
||||
|
||||
## Filename-collision gotcha (execute_code + read_file)
|
||||
|
||||
`hermes_tools.read_file` inside `execute_code` returns a different schema than the
|
||||
top-level `read_file` tool. Inside a script:
|
||||
|
||||
```python
|
||||
from hermes_tools import read_file
|
||||
r = read_file("/path/to/file")
|
||||
# Schema: {"status": ..., "message": ..., "path": ..., "dedup": ..., "content_returned": ...}
|
||||
# NO "content" key. Use the top-level read_file tool, OR use terminal cat.
|
||||
```
|
||||
|
||||
**Workaround patterns:**
|
||||
|
||||
```python
|
||||
# Pattern 1: terminal cat to a temp file, then open()
|
||||
import subprocess
|
||||
subprocess.run(["cp", "/path/to/file", "/tmp/working.txt"])
|
||||
with open("/tmp/working.txt") as f:
|
||||
content = f.read()
|
||||
|
||||
# Pattern 2: shell-out to the file directly
|
||||
with open("/path/to/file") as f:
|
||||
content = f.read() # works in execute_code without hermes_tools
|
||||
```
|
||||
|
||||
This gotcha caused patch errors in a multi-file edit session: a patch string was
|
||||
constructed from `r["content"]` which didn't exist inside `execute_code`. Switched
|
||||
to `subprocess.run` + `with open()` to read reliably.
|
||||
|
||||
## Pre-dispatch model and config
|
||||
|
||||
- **Always pass `--model claude-opus-4-8` explicitly.** Profile defaults drift silently.
|
||||
- **Always set `--max-turns`.** Default 30 is good for analysis. Lower for trivial
|
||||
questions; higher (50+) for deep architectural reviews.
|
||||
- **Always wrap with `timeout 280`.** Prevents runaway hangs. SSH itself has 300s.
|
||||
- **Always add `|| true` after claude invocation.** `set -e` would kill the script
|
||||
on non-zero exit, but the error JSON is still parseable.
|
||||
- **Always use `mktemp` for temp files on the remote.** `/tmp/ask-claude-q.txt` is
|
||||
a fixed path that concurrent Hermes sessions clobber.
|
||||
|
||||
## Multi-turn session lifecycle
|
||||
|
||||
- First `ask-claude` call in a Hermes session → fresh session (no `--resume`).
|
||||
- Every subsequent call in the same Hermes session → `--resume <session_id>`.
|
||||
- Sessions auto-expire after ~5 hours of inactivity. No cleanup needed.
|
||||
- If the operator starts a new Hermes session (`.hermes/sessions/` rotates),
|
||||
the Claude session is also gone — `--resume` will fail.
|
||||
- For maximum continuity, capture `session_id` in the operator-visible relay
|
||||
text so the operator can resume manually if the Hermes session restarts.
|
||||
|
||||
## Usage and context alerts
|
||||
|
||||
Apply on every turn:
|
||||
|
||||
| Check | Threshold | Action |
|
||||
|---|---|---|
|
||||
| Context % (from JSON envelope) | ≥ 80% | Warn: "wrap up or start fresh" |
|
||||
| Session 5h utilization (OAuth API) | ≥ 80% | Warn + show reset time, offer Sonnet |
|
||||
| Weekly 7d utilization (OAuth API) | ≥ 90% | Critical warning + reset time |
|
||||
| Unavailable (error_budget / rate-limit) | N/A | Report exact reset time |
|
||||
|
||||
**The OAuth usage API aggressively rate-limits.** Call at most every ~5 minutes.
|
||||
Cache the last good value. Swallow all errors (429s, timeouts). Never gate a turn
|
||||
on this call.
|
||||
|
||||
## Common error patterns
|
||||
|
||||
- `error_max_turns` — question too complex, increase `--max-turns` or simplify.
|
||||
`is_error: false`, but no `result` field — check `subtype` explicitly.
|
||||
- `error_budget` — hit spending cap, check Pro limits.
|
||||
- Empty response — timeout (increase from 280s), OOM, or crash.
|
||||
- Non-JSON response — SSH dropped mid-call, Claude crashed before writing output.
|
||||
- `ask.sh` returns `{"is_error": true, "error": "no Claude output"}` but direct
|
||||
`claude -p` works — wrapper has a known failure mode. Fall back to direct:
|
||||
`ssh n8n@10.0.0.28 'cd ~/claude/hermes_support && timeout 280 /home/n8n/.local/bin/claude -p "$(cat /tmp/q.txt)" --output-format json --model claude-opus-4-8 --max-turns 30 || true'`
|
||||
|
||||
## When the operator pushes back
|
||||
|
||||
After applying Claude's recommendations, ALWAYS emit the disagreement scan (see
|
||||
SKILL.md §3.5). Skipping this is a failure mode — both silently-accepting and
|
||||
silently-dropping are bugs. The scan is mandatory before declaring a Claude turn
|
||||
resolved.
|
||||
Reference in New Issue
Block a user