claude-runner

claude-runner is a skill for Claude Code, Codex from aspenkit/aspens. It costs 36 tokens per session (1,742 once invoked), scanned A, original, MIT.

The command-line layer that runs Claude or Codex, sends them prompts, reads their streamed results, and safely extracts files they produce.

In plain words
What is it for?
Use it to load prompts, run Claude or Codex commands, process JSON event streams, write skill files, and restrict generated output to allowed paths.
Why use it?
Different command-line tools return structured output in different formats, and generated file paths need validation. This layer handles that communication and file handling in one place.

Skill for Claude CodeCodex

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add skills/aspenkit/aspens/claude-runner
Any agent
npx skills add aspenkit/aspens --skill claude-runner
Clone the repo
git clone --depth 1 https://github.com/aspenkit/aspens

Made for: Claude Code, Codex.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for claude-runner

README.md
[![agentmods](https://agentmods.dev/badge/skills/aspenkit/aspens/claude-runner.svg)](https://agentmods.dev/skills/aspenkit/aspens/claude-runner)
Your own site
<a href="https://agentmods.dev/skills/aspenkit/aspens/claude-runner"><img src="https://agentmods.dev/badge/skills/aspenkit/aspens/claude-runner.svg" alt="Measured on agentmods" height="20"></a>
Per session 36 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 1,742 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.00036 $0.01742
Opus 5 $0.00018 $0.00871
Sonnet 5 $0.00007 $0.00348
Haiku 4.5 $0.00004 $0.00174

Measured 4d ago against content hash 2f2301fbdc5d, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

claude-runner scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 4d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

.agents/skills/claude-runner/SKILL.md · 58 lines

How it starts

The opening of the file, as written. The whole thing — 58 lines — stays where its author put it; the contents beside it link to each section on GitHub.

You are working on the CLI execution layer — the bridge between assembled prompts and the claude -p / codex exec CLIs, plus skill file I/O.

Key Concepts

  • Stream-JSON protocol (Claude): runClaude() always passes --verbose --output-format stream-json. Output is NDJSON: type: 'result' has final text + usage; type: 'assistant' has text/tool_use blocks; type: 'user' has tool_result blocks.
  • JSONL protocol (Codex): runCodex() spawns codex exec --json --sandbox read-only --ephemeral. The --ask-for-approval never flag is conditionally included based on capability detection (see below). Prompt is passed via stdin ('-' placeholder arg) to avoid shell arg length limits. Stdin write happens after event handlers are attached so fast failures are captured. Events: item.completed/item.updated with normalized types.
  • Codex capability detection: getCodexExecCapabilities() (internal, cached) runs codex exec --help and checks if --ask-for-approval appears in the help text. Result is cached in module-level codexExecCapabilities variable. If the help check fails (e.g., codex not installed), capabilities default to { supportsAskForApproval: false }. runCodex() only adds --ask-for-approval never when supportsAskForApproval is true.
  • Unified routing: runLLM(prompt, options, backendId) is the shared entry point — dispatches to runClaude() or runCodex() based on backendId. Exported from runner.js so command handlers no longer need local routing helpers.
  • Codex internals (private): normalizeCodexItemType() converts PascalCase/kebab-case to snake_case. collectCodexText() recursively extracts text from nested event content. Both are internal to runner.js.
  • Prompt templating: loadPrompt(name, vars) resolves {{partial-name}} from src/prompts/partials/ first, then substitutes {{varName}} from vars. Target-specific vars (skillsDir, skillFilename, instructionsFile, configDir) are passed by command handlers.
  • File output parsing: Primary: <file path="...">content</file> XML tags. Fallback: <!-- file: path --> comment markers. parseFileOutput(output, allowedPaths) accepts optional { dirPrefixes, exactFiles } to override default allowed paths.
  • Path sanitization: sanitizePath(rawPath, allowedPaths) (internal) blocks .. traversal, absolute paths. Defaults: .claude/ prefix + AGENTS.md exact. Multi-target callers pass expanded allowed paths via getAllowedPaths() from target.js.
  • Validation: validateSkillFiles() checks for truncation (XML tag collisions), missing frontmatter, missing sections, bad file path references.
  • Skill rules generation: extractRulesFromSkills() reads all skills via skill-reader.js, produces skill-rules.json (v2.0) with file patterns, keywords, and intent patterns.
  • Domain patterns: generateDomainPatterns() converts file patterns to bash detect_skill_domain() function using BEGIN/END markers.
  • Trigger parsing precedence: parseTriggersFrontmatter(content) returns { filePatterns, keywords, alwaysActivate } parsed from a triggers: block in YAML frontmatter (supports block lists, inline arrays, and alwaysActivate: true for the base skill); returns null when no triggers: key exists. parseActivationPatterns and parseKeywords prefer this frontmatter when present and fall back to legacy ## Activation / Keywords: line parsing for older skills.
  • Settings merge: mergeSettings() merges aspens hook config into existing settings.json. Detects aspens-managed hooks by ASPENS_HOOK_MARKERS (skill-activation-prompt, graph-context-prompt, post-tool-use-tracker, save-tokens-statusline, save-tokens-prompt-guard, save-tokens-precompact). Also handles statusLine merging — replaces existing statusLine only if the current one is aspens-managed (detected by isAspensHook), preserving user-custom statusLine configs. After merging hooks, dedupeAspensHookEntries() removes duplicate aspens-managed entries per event type.
  • Directory-scoped writes: writeTransformedFiles() handles files outside .claude/ (e.g., src/billing/AGENTS.md) with explicit path allowlist — only AGENTS.md, AGENTS.md exact files and .claude/, .agents/, .codex/ prefixes are permitted.
  • findSkillFiles matching: Only matches the exact skillFilename (e.g., skill.md or SKILL.md), not arbitrary .md files in the skills directory.

Read the full file on GitHub · 58 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 4d ago First seen · 58 lines · 36 tokens per session scan A 2f2301fbdc5d

Subscribe to this mod's changes

claude-runner is a skill published in the GitHub repository aspenkit/aspens (99 stars, last pushed 19d ago), licensed MIT. It adds 36 tokens to every session and 1,742 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.