Catalog PyPI
PACKAGE EXPLORERView in registry

aicraft

PyPI

Run coding agents (Claude Code, Codex, Aider, OpenHands, …) against prompts in container sandboxes via Harbor

agentcoding-agentharborllmsandbox
Versions collected1
Direct dependencies7From release 0.1.3
Last observed21 Oct, 10:20 UTC

README

Version 0.1.3 documentation

aicraft

Run coding agents (Claude Code, Codex, Aider, OpenHands, …) against prompts in container sandboxes. A thin Python library + CLI on top of the Harbor framework, focused on ad-hoc single-prompt runs rather than full benchmark evaluation.

Status: alpha. API and CLI may shift between 0.1.x releases. Pin minor versions if you depend on it.

Why this exists

Harbor itself is built around full benchmark lifecycles: scaffolding a task directory, running an agent over a dataset, scoring with a verifier, publishing trajectories. That's heavy when all you want is "run agent X on prompt Y, give me the answer."

aicraft flips the abstraction:

  • Inline prompt or --prompt-file instead of a hand-built task directory
  • Verifier disabled by default
  • Auto-synthesizes the minimal Harbor task structure under the hood
  • ATIF-aware final-text extraction (works across any agent that emits ATIF)
  • Mount allowlist enforcement (refuses to mount paths outside configured roots)
  • Provider presets (--provider openrouter etc.) for routing OpenAI-protocol agents through aggregator gateways

It's the opinionated, ad-hoc-friendly subset of Harbor — like gh is to a git push origin <branch> && curl github.com/... chain.

Install

pip install aicraft

aicraft requires Python 3.12+ and a working Docker daemon (or Podman with the Docker compatibility socket — set DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock). Harbor itself spawns each agent in a Docker container.

Usage

Library

import asyncio
from pathlib import Path
from aicraft import AgentRunner, AgentConfig, MountSpec

async def main():
    runner = AgentRunner()
    result = await runner.run(AgentConfig(
        prompt="Summarize the structure of /workspace/code in one paragraph.",
        agent="claude-code",
        mounts=[MountSpec(host=Path("/data/repo"), container=Path("/workspace/code"))],
        timeout_s=600,
    ))
    print(result.status)         # "completed" | "timeout" | "error"
    print(result.final_text)     # agent's textual reply (extracted from ATIF)
    print(result.trajectory_path)  # full trajectory on disk

asyncio.run(main())

CLI

# Inline prompt
aicraft run -a claude-code "Find dead code in this repo"

# Prompt from a file
aicraft run -a codex -M gpt-5 -f ./prompt.md

# With a mounted code directory
AICRAFT_MOUNT_ROOTS=/data/repos aicraft run -a claude-code \
  "Refactor the parser for readability" \
  --mount /data/repos/foo:/workspace/code:ro

# Specify model and a higher timeout, write structured result to file
aicraft run -a claude-code "..." \
  --model claude-sonnet-4-7 \
  --timeout 1800 \
  --output ./result.json

# Bump the container memory limit for memory-hungry agents/models
aicraft run -a claude-code "..." --memory-mb 8192

# Route an OpenAI-protocol agent through OpenRouter for open-weight models
OPENROUTER_API_KEY=sk-or-... aicraft run \
  -a codex -M deepseek/deepseek-chat --provider openrouter \
  "Describe the bug in /workspace/buggy.py and fix it" \
  --mount /tmp/scratch:/workspace:rw

# See installed agents
aicraft list-agents

# Locate a previously-run trajectory on disk
aicraft trajectory aicraft-3a2b1c0d9e8f

Mount syntax: host:container[:ro|rw] — default is ro. Pass :rw explicitly when the agent needs to write back.

Output

aicraft run prints a JSON document to stdout for pipeline use:

{
  "status": "completed",
  "final_text": "def reverse_string(s: str) -> str:\n    return s[::-1]",
  "trajectory_path": "/path/to/trajectories/aicraft-7dad38f46662",
  "duration_s": 65.1,
  "trial_id": "aicraft-7dad38f46662",
  "error": null
}

…and a human-readable banner to stderr so the agent's reply is easy to spot amid debug logs:

════════════════════════════════════════════════════════════════════════
 AGENT OUTPUT  [OK]  trial=aicraft-7dad38f46662  65.1s
════════════════════════════════════════════════════════════════════════
def reverse_string(s: str) -> str:
    return s[::-1]
════════════════════════════════════════════════════════════════════════

Exit codes: 0 on completed, 1 on timeout / error, 2 on a pre-flight config issue (mount not allowed, missing required model, unknown provider).

The trajectory directory contains everything Harbor captured: the ATIF trajectory.json, the agent's raw session logs, and any verifier artifacts. For an aicraft run there's no verifier output, but the ATIF trajectory has the full tool-call history.

Configuration

VariablePurposeDefault
AICRAFT_MOUNT_ROOTSColon-separated absolute host paths permitted as mount sources. Empty means no mounts allowed.empty
AICRAFT_TRAJECTORY_DIRWhere captured trajectories are stored. Override per-call with --trajectory-dir../trajectories/ (cwd)
OPENAI_API_KEY, OPENAI_BASE_URL, ANTHROPIC_API_KEY, ANTHROPIC_BASE_URL, GEMINI_API_KEY, GOOGLE_API_KEY, CLAUDE_CODE_OAUTH_TOKENStandard provider env vars consumed by Harbor agents.—
OPENROUTER_API_KEY, FIREWORKS_API_KEY, TOGETHER_API_KEY, GROQ_API_KEYProvider-specific keys consumed by --provider <name>.—

Provider presets

--provider <name> rewrites OPENAI_BASE_URL and OPENAI_API_KEY from a friendly name plus a provider-specific env var, so OpenAI-protocol agents (codex, copilot-cli) can route through aggregator gateways without manual env juggling. Anthropic-protocol agents (claude-code) read ANTHROPIC_* directly and need separate setup.

PresetBase URLKey env var
openrouterhttps://openrouter.ai/api/v1OPENROUTER_API_KEY
fireworkshttps://api.fireworks.ai/inference/v1FIREWORKS_API_KEY
togetherhttps://api.together.xyz/v1TOGETHER_API_KEY
groqhttps://api.groq.com/openai/v1GROQ_API_KEY

Limitations

See GOTCHAS.md for the full list with reproduction steps and workarounds. Highlights:

  • First run per agent is slow — Harbor re-installs the agent CLI in a fresh container on every trial (~45–55s for claude-code/codex). Image build is cached; container is fresh.
  • Rootless Podman + claude-code — the agent runs fine, but trajectory ingestion fails reading session JSONL files (claude-code writes them at 0600, and rootless Podman's userns mapping makes them unreadable from the host). Use Docker for claude-code, or other agents (codex, aider, nop) on Podman — they're unaffected.
  • final_text for non-ATIF agents — may be empty; the trajectory directory still has the full record.
  • Codex requires an explicit --model — Harbor's codex agent has no default. aicraft pre-validates this in <1s.
  • --provider is OpenAI-protocol only — claude-code (Anthropic protocol) needs ANTHROPIC_BASE_URL + ANTHROPIC_API_KEY set manually for gateways like OpenRouter.
  • harbor#1514 — Defer litellm/aiohttp imports to avoid ~25s startup overhead

License

MIT — see LICENSE.

Downloads & popularity

1downloads
1-day window · source-reported counts20 Oct 2026
1260
2026-07-23: 3 · observed 2026-10-21T14:38:53.1420284Z · period 2026-07-23–2026-07-232026-07-24: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-07-24–2026-07-242026-07-27: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-07-27–2026-07-272026-07-28: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-07-28–2026-07-282026-07-30: 3 · observed 2026-10-21T14:38:53.1420284Z · period 2026-07-30–2026-07-302026-08-01: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-01–2026-08-012026-08-02: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-02–2026-08-022026-08-03: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-03–2026-08-032026-08-04: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-04–2026-08-042026-08-06: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-06–2026-08-062026-08-09: 5 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-09–2026-08-092026-08-14: 4 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-14–2026-08-142026-08-15: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-15–2026-08-152026-08-16: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-16–2026-08-162026-08-17: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-17–2026-08-172026-08-19: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-19–2026-08-192026-08-20: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-20–2026-08-202026-08-21: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-21–2026-08-212026-08-23: 12 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-23–2026-08-232026-08-24: 5 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-24–2026-08-242026-08-25: 3 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-25–2026-08-252026-08-27: 8 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-27–2026-08-272026-08-31: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-08-31–2026-08-312026-09-01: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-01–2026-09-012026-09-06: 6 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-06–2026-09-062026-09-07: 4 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-07–2026-09-072026-09-08: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-08–2026-09-082026-09-09: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-09–2026-09-092026-09-13: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-13–2026-09-132026-09-14: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-14–2026-09-142026-09-16: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-16–2026-09-162026-09-18: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-18–2026-09-182026-09-19: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-19–2026-09-192026-09-21: 8 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-21–2026-09-212026-09-24: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-24–2026-09-242026-09-26: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-26–2026-09-262026-09-27: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-27–2026-09-272026-09-28: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-28–2026-09-282026-09-30: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-09-30–2026-09-302026-10-02: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-02–2026-10-022026-10-06: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-06–2026-10-062026-10-08: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-08–2026-10-082026-10-09: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-09–2026-10-092026-10-10: 6 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-10–2026-10-102026-10-13: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-13–2026-10-132026-10-14: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-14–2026-10-142026-10-15: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-15–2026-10-152026-10-17: 2 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-17–2026-10-172026-10-20: 1 · observed 2026-10-21T14:38:53.1420284Z · period 2026-10-20–2026-10-20
23 Jul20 Oct

pypistats · 49 observations shown. Missing days are unknown. Source category: overall: without mirrors.

View observed values
Date / source periodValueObserved at
2026-10-20 – 2026-10-2012026-10-21T14:38:53.1420284Z
2026-10-17 – 2026-10-1722026-10-21T14:38:53.1420284Z
2026-10-15 – 2026-10-1512026-10-21T14:38:53.1420284Z
2026-10-14 – 2026-10-1412026-10-21T14:38:53.1420284Z
2026-10-13 – 2026-10-1312026-10-21T14:38:53.1420284Z
2026-10-10 – 2026-10-1062026-10-21T14:38:53.1420284Z
2026-10-09 – 2026-10-0912026-10-21T14:38:53.1420284Z
2026-10-08 – 2026-10-0812026-10-21T14:38:53.1420284Z
2026-10-06 – 2026-10-0612026-10-21T14:38:53.1420284Z
2026-10-02 – 2026-10-0222026-10-21T14:38:53.1420284Z
2026-09-30 – 2026-09-3022026-10-21T14:38:53.1420284Z
2026-09-28 – 2026-09-2822026-10-21T14:38:53.1420284Z
2026-09-27 – 2026-09-2712026-10-21T14:38:53.1420284Z
2026-09-26 – 2026-09-2612026-10-21T14:38:53.1420284Z
2026-09-24 – 2026-09-2412026-10-21T14:38:53.1420284Z
2026-09-21 – 2026-09-2182026-10-21T14:38:53.1420284Z
2026-09-19 – 2026-09-1912026-10-21T14:38:53.1420284Z
2026-09-18 – 2026-09-1812026-10-21T14:38:53.1420284Z
2026-09-16 – 2026-09-1622026-10-21T14:38:53.1420284Z
2026-09-14 – 2026-09-1412026-10-21T14:38:53.1420284Z
2026-09-13 – 2026-09-1322026-10-21T14:38:53.1420284Z
2026-09-09 – 2026-09-0912026-10-21T14:38:53.1420284Z
2026-09-08 – 2026-09-0822026-10-21T14:38:53.1420284Z
2026-09-07 – 2026-09-0742026-10-21T14:38:53.1420284Z
2026-09-06 – 2026-09-0662026-10-21T14:38:53.1420284Z
2026-09-01 – 2026-09-0122026-10-21T14:38:53.1420284Z
2026-08-31 – 2026-08-3112026-10-21T14:38:53.1420284Z
2026-08-27 – 2026-08-2782026-10-21T14:38:53.1420284Z
2026-08-25 – 2026-08-2532026-10-21T14:38:53.1420284Z
2026-08-24 – 2026-08-2452026-10-21T14:38:53.1420284Z
2026-08-23 – 2026-08-23122026-10-21T14:38:53.1420284Z
2026-08-21 – 2026-08-2122026-10-21T14:38:53.1420284Z
2026-08-20 – 2026-08-2012026-10-21T14:38:53.1420284Z
2026-08-19 – 2026-08-1912026-10-21T14:38:53.1420284Z
2026-08-17 – 2026-08-1722026-10-21T14:38:53.1420284Z
2026-08-16 – 2026-08-1622026-10-21T14:38:53.1420284Z
2026-08-15 – 2026-08-1522026-10-21T14:38:53.1420284Z
2026-08-14 – 2026-08-1442026-10-21T14:38:53.1420284Z
2026-08-09 – 2026-08-0952026-10-21T14:38:53.1420284Z
2026-08-06 – 2026-08-0622026-10-21T14:38:53.1420284Z
2026-08-04 – 2026-08-0412026-10-21T14:38:53.1420284Z
2026-08-03 – 2026-08-0312026-10-21T14:38:53.1420284Z
2026-08-02 – 2026-08-0212026-10-21T14:38:53.1420284Z
2026-08-01 – 2026-08-0122026-10-21T14:38:53.1420284Z
2026-07-30 – 2026-07-3032026-10-21T14:38:53.1420284Z
2026-07-28 – 2026-07-2812026-10-21T14:38:53.1420284Z
2026-07-27 – 2026-07-2722026-10-21T14:38:53.1420284Z
2026-07-24 – 2026-07-2422026-10-21T14:38:53.1420284Z
2026-07-23 – 2026-07-2332026-10-21T14:38:53.1420284Z

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.1.312 Jul 20267

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
kashifpk/aicraft

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 21 Oct, 10:20 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:2a5c54453f8b9a167b16c0a925062d078f6ea7bd10b95d2e239e19fb61eccf0b