Skip to content
Back to skills

Features

ASecurity

This is not a claude-mux feature - it's instruction content to hand to Hermes (or any other external, non-Claude agent) so it can build its own skill for calling the official `claude` CLI directly in non-interactive mode. No claude-mux code is involved in this path; claude-mux is only the source of the shared safety template both this path and the future `--route` feature use (`dev/features/external-agent-untrusted-framing.txt`). > **EXAMPLE CONTENT, NOT A DROP-IN FILE.** The rules below are ...

  • 10 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 30, 2026
ai-agentsrustshelltestingapi

Works with

  • claude code
  • cli
  • api

Security analysis

A100/100

Pro scans all 21 files and shows the line behind each finding

Scanned September 30, 2026

npx -y skills add pereljon/claude-mux --skill features --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Features?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Features
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/pereljon-features/badge)](https://www.skillsdirectory.com/skills/pereljon-features)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
kind: investigation
feature: hermes-claude-p-skill
status: DRAFTED 2026-09-11, REVISED 2026-09-11 (incoming/ + atomic marker-file async
  delivery). Instruction content for an EXTERNAL, non-claude-mux tool (Hermes) to build its
  own skill for calling `claude -p` directly. No claude-mux code required or touched.
  Companion/interim path alongside the still-designed, unbuilt `external-prompt-routing`
  (`--route`) feature - not a replacement for it. **This file is an EXAMPLE / reference
  requirements document, not a drop-in skill file.** Its format may not match whatever
  native skill-definition format Hermes actually uses (unknown at time of writing - the
  claude-mux side has no visibility into Hermes's own skill schema). Whoever hands this off
  should have Hermes (or its maintainer) WRITE AN APPROPRIATE, NATIVELY-FORMATTED skill file
  based on the content and rules below, not assume this markdown file is consumable as-is.
related: external-prompt-routing
---

# Hermes skill: talking to Claude Code sessions via `claude -p`

This is not a claude-mux feature - it's instruction content to hand to Hermes (or any
other external, non-Claude agent) so it can build its own skill for calling the official
`claude` CLI directly in non-interactive mode. No claude-mux code is involved in this path;
claude-mux is only the source of the shared safety template both this path and the future
`--route` feature use (`dev/features/external-agent-untrusted-framing.txt`).

> **EXAMPLE CONTENT, NOT A DROP-IN FILE.** The rules below are the *requirements* a Hermes
> skill needs to satisfy - self-identification, the framing file, the async delivery
> contract, the usage-scope constraint, etc. They are written as plain instructional prose,
> not in any particular skill-definition syntax. If Hermes has its own native skill format
> (its own frontmatter conventions, invocation model, file layout - unknown from the
> claude-mux side), **translate this content into that format rather than using this file
> verbatim.**

## The instruction content (give this to Hermes)

---

**Calling Claude Code sessions from Hermes**

You can delegate a discrete task or question to a Claude Code session by invoking the
`claude` CLI directly in non-interactive mode. Follow these rules:

1. **Always identify yourself in the prompt itself.** Start every prompt you send with a
   clear statement of who you are, e.g. `"I am Hermes, an autonomous agent, not a human
   operator or another Claude Code session."` This is in addition to, not instead of, the
   untrusted-content framing below - self-identification tells the receiving worker WHO is
   asking; the framing tells it HOW to treat what you're asking.

2. **Always pass the untrusted-content framing file.** Every call must include:
   `--append-system-prompt-file <path-to-external-agent-untrusted-framing.txt>`
   using the exact template maintained at
   `dev/features/external-agent-untrusted-framing.txt` in the claude-mux repo (get a current
   copy - don't hand-roll your own wording, so this stays in sync with the canonical
   version). This tells the worker to treat your prompt as external, untrusted input rather
   than blindly-trusted instructions - a real safety property, not a formality.

3. **Optionally pass a handoff file for extra context.** If you have more context to supply
   than fits naturally in the prompt string itself (background, prior state, structured
   data), write it to a file and pass it as a SECOND, separate
   `--append-system-prompt-file <handoff-file>` argument (or merge it into one file with the
   framing content, in that order, if your invocation only supports one instance of the
   flag - verify which before relying on it; this was not confirmed either way during
   design). Keep the framing content's protection intact regardless of how you merge -
   don't let handoff content dilute or precede it.

4. **Run in the target project's directory.** `cd` (or otherwise set the working directory)
   to the specific Claude Code project you're targeting before invoking `claude`. CLAUDE.md
   and project context load automatically from the working directory - you do not need to
   supply project context yourself.

5. **Choose sync or async per call:**
   - **Synchronous** - `claude -p --output-format json "prompt"`, wait for it to exit, read
     the `result` field from its JSON stdout. Use this when you need the answer before your
     own next step.
   - **Asynchronous** - background the call. Deliver the result **only into your own
     `incoming/` folder** (wherever your own configuration keeps it - this instruction
     doesn't assume a path, since that folder is yours to own, not claude-mux's). Write the
     captured `result` text to `incoming/[FILENAME].txt` (or whatever extension you
     prefer). **Only after that file is completely written**, `touch` a companion marker
     file `incoming/.[FILENAME]` - the same base filename as a hidden dotfile, empty, no
     content needed. The marker's mere existence, not its content, is the completion
     signal.
   - **When polling for an async result, wait for the `.[FILENAME]` marker to appear -
     never poll `[FILENAME].txt` directly.** A file being written (e.g. via shell
     redirection) can exist on disk before it's fully flushed; reading it mid-write risks a
     partial or corrupt result. Touching a separate marker only after the write completes
     gives an atomic, race-free signal - read `[FILENAME].txt` only once its `.[FILENAME]`
     marker exists.

6. **This is for specific work and questions - not a continuous processing pipeline.**
   Treat each call as a discrete, bounded delegation a human would otherwise type into
   Claude Code directly - not sub-second bulk automation, not a polling/streaming loop, not
   a substitute for a real integration. This isn't an arbitrary style preference: Anthropic's
   Consumer Terms restrict "automated or non-human means" access except via an API key or
   where explicitly permitted, and the official CLI's own "script and automate" support is
   the reason this works at all. Staying at the scale of "occasional, purposeful delegation"
   keeps this squarely inside that intended use; turning it into a continuous pipeline is the
   kind of usage pattern that has drawn account-level enforcement for other tools. If your
   use case genuinely needs continuous/high-volume automation, that needs its own design
   (e.g. an Anthropic API key for that workload) - don't scale this pattern up to meet it.

7. **Each call is stateless unless you carry context yourself.** `claude -p` does not
   remember prior calls. If you need continuity across a sequence of related requests,
   include what the worker needs to know in the prompt or handoff file yourself (e.g. "on
   <date> you told me X") - there is no built-in session memory in this direct-calling
   pattern.

8. **Handle failures explicitly, don't retry in a loop.** If a call errors, times out, or
   the target project doesn't exist, surface that clearly and stop - don't auto-retry
   rapidly, which would itself become the "continuous pipeline" pattern rule 6 warns against.

---

## Why these specific rules, for whoever maintains this instruction later

- **Rules 1-2 (self-ID + framing file)** were the user's original request, confirmed against
  live testing during this feature's design: `claude -p` does NOT load any framing on its
  own - if Hermes doesn't apply this itself, nothing does, since no claude-mux code sits in
  this path.
- **Rule 3 (handoff file)** was the user's original idea. Whether `--append-system-prompt-file`
  genuinely composes across two separate invocations of the flag (vs. the later one silently
  winning) was being tested empirically during design and was interrupted before a
  conclusive result landed - **this is unverified, flagged explicitly in the rule text
  rather than asserted as fact.** Re-verify before relying on it; see Open Questions.
- **Rule 4 (CLAUDE.md loads automatically)** confirmed live during design - `claude -p` in a
  project directory correctly reflected that project's own CLAUDE.md content with no extra
  flags.
- **Rule 5 (sync/async)** was revised 2026-09-11: async delivery now writes to the caller's
  own `incoming/` folder with an atomic `.` marker-file completion signal, replacing an
  earlier draft that used a shared `/tmp/claude-mux/<id>.txt` path. `external-prompt-routing.md`
  was updated the same day to match (its `--wait`-less mode now takes a required
  `--incoming-dir DIR` argument and uses the identical `<id>.txt` + `.<id>` marker
  contract) - the two paths are consistent again as of this revision. (The divergence
  existed only briefly, between the two edits on 2026-09-11 - noted here for the record,
  not as an open problem.)
  The marker-file pattern (write the payload, then atomically signal completion via a
  separate empty file) mirrors what claude-mux's own codebase already does for similar
  races elsewhere (e.g. `mkdir`-based atomic locks) - the same shape of problem, applied to
  file *delivery* instead of *locking*: a reader must never be able to observe a
  partially-written payload.
- **Rule 6 (not a pipeline)** operationalizes the account-suspension risk research from the
  `external-prompt-routing` design - the same reasoning applies here, arguably more directly,
  since there's no claude-mux authorization gate in this path to enforce restraint
  mechanically. The instruction has to carry that discipline on its own.
- **Rules 7-8** are additions beyond the original ask, worth flagging as new: stateless-by-
  default (this pattern has no continuity mechanism at all, unlike the designed `--route`
  feature's single-slot cache) and no-auto-retry (a failure-handling gap that, left
  unaddressed, could accidentally violate rule 6).

## Open questions (resolve before treating this as final)

1. **Does `--append-system-prompt-file` actually compose across two invocations**, or does
   the second one win/overwrite? Testing this was interrupted mid-design. Rule 3 is written
   defensively (verify first) rather than asserting an unconfirmed behavior.
2. **Distribution mechanism**: how does Hermes actually obtain a current copy of
   `external-agent-untrusted-framing.txt`? Not yet decided - options include: a stable URL,
   a file Hermes is given once at setup, or something else. Left open.
3. **Should this doc get folded into `external-prompt-routing.md`'s scope, or stay a
   separate, standalone deliverable?** Kept as its own `kind: investigation` doc for now
   since it has a different audience (external agent maintainers, not claude-mux
   implementers) and a different build status (usable today vs. designed-but-unbuilt).
4. ~~`incoming/` vs `/tmp/claude-mux/` divergence~~ - **RESOLVED 2026-09-11**:
   `external-prompt-routing.md` updated the same day to the matching `--incoming-dir` +
   marker-file contract. See "Why these specific rules" above.
5. **Where exactly is "its own `incoming/` folder"?** This instruction deliberately does not
   assume a path, since claude-mux has no visibility into Hermes's directory layout - but
   whoever translates this into Hermes's native skill format needs to resolve this to an
   actual, concrete path (or a config value Hermes already has) before it's usable.

Files in this skill

  • INDEX.md8.2 KB
  • auto-restore-tests.md8.1 KB
  • auto-restore.md12.8 KB
  • caller-restart-resume-investigation.md8.8 KB
  • caller-restart-resume-race-tests.md5.8 KB
  • caller-restart-resume-race.md9.5 KB
  • claude-code-upgrade-detection-tests.md4.1 KB
  • claude-code-upgrade-detection.md6.3 KB
  • clear-ready-handshake-tests.md4.2 KB
  • clear-ready-handshake.md6.6 KB
  • context-cost-awareness.md5.6 KB
  • cross-cli-coders-tests.md8.6 KB
  • cross-cli-coders.md36.3 KB
  • external-agent-untrusted-framing.txt836 B
  • external-prompt-routing-tests.md6.2 KB
  • external-prompt-routing.md16.6 KB
  • herdr-competitive-analysis.md6.2 KB
  • hermes-claude-p-skill.md11.1 KB
  • home-prompt-split-tests.md6.8 KB
  • home-prompt-split.md14.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…