{"owner":"PrimeIntellect-ai","repo":"prime-agent","hasSkills":true,"totalSkillsCount":19,"totalTokensCount":15759,"categories":["root-instruction","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md","skills/agent-message/SKILL.md","skills/agent-observe/SKILL.md","skills/attach-image/SKILL.md","skills/compact/SKILL.md","skills/edit/SKILL.md","skills/factory/SKILL.md","skills/goal/SKILL.md","skills/mcp/SKILL.md","skills/prime-intellect/SKILL.md","skills/prime-intellect/references/compute.md","skills/prime-intellect/references/environments.md","skills/prime-intellect/references/inference.md","skills/prime-intellect/references/sandboxes.md","skills/refine/SKILL.md","skills/rlm-heartbeat/SKILL.md","skills/skill-creator/SKILL.md","skills/skill-creator/references/python-skills.md","skills/websearch/SKILL.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\nDevelopment rules for Prime Agent (Rust) on PrimeIntellect-ai/prime-agent, branch `main`.\nEvery contributor (human or agent) must read this before working on this repo.\n\n## Repository\n\n- **Never set git identity for commits to this repo's history.** Agents must not set\n  `user.name`/`user.email` (config or `-c`) or `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/\n  `GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` for commits that land in this repository.\n  Those commits carry the identity of the ambient git config. If such a commit fails for a\n  missing identity, report it instead of adding config. Allowed: the `*_DATE` variables\n  (the golden corpus pins them for reproducibility), throwaway temp repos created by\n  tests, and the release automation's bot identity.\n- **Never add `Co-authored-by` trailers** — not in commit messages, not in squash\n  suggestions, not as attribution for work merged from branches. A PR's commits carry\n  one identity: the ambient git config's. Fabricated or hand-written trailers (including\n  noreply forms) misattribute commits to unrelated GitHub accounts.\n- The repo is PrimeIntellect-ai/prime-agent; the Rust implementation lives on the `main` branch.\n- PRs go to the org repo with base `main`:\n  `gh pr create --repo PrimeIntellect-ai/prime-agent --base main`.\n- CI runs on the org's billing: `.github/workflows/continuous.yml` on `main` pushes and\n  `release.yml` on version tags.\n- Parity ground truth is unchanged: a read-only checkout of the TS implementation (this\n  repo at tag `v0.9.8`, the last TS release before the Rust port merged to `main`). Clone\n  it to `~/prime-agent`, the conventional location the parity scripts and code fall back\n  to; tooling that honors an override reads `PA_TS_REFERENCE`.\n\n## Style and structure\n\n- Workspace crates are prefixed `pa-`. The hard ownership rules: one owned area per crate,\n  pa-types is the only shared crate, cycle-free dependency direction, minimal public APIs,\n  no god-modules. The dependency direction is pinned in the Crates table below; each crate's\n  README.md states its scope, non-goals, and public API surface.\n- Prefer private modules with an explicitly exported public crate API. Internals are `pub(crate)`.\n- Aim for files under 2,000 lines, tests included. The 2,000-2,100 range is a soft review\n  signal, not a merge limit: when adding to an already-large file, consider splitting by\n  responsibility rather than growing it further. Move related tests and docs with extracted code.\n- Name modules for what they own, not `utils` or `common`. Follow existing structure: in\n  `crates/pa-core/src/kernel/manager/`, `mod.rs` connects `execution.rs`, `requests.rs`, and\n  `teardown.rs`; put a new kernel-manager concern beside them. In\n  `crates/pa-core/src/cron/store/`, `mod.rs` connects `heartbeat.rs`, `jobs.rs`, and\n  `session_artifacts.rs`; keep storage work there rather than growing the scheduler.\n- Inline format args: always prefer `format!(\"{x}\")` over positional.\n- Collapse if statements per clippy::collapsible_if.\n- Prefer method references over closures per clippy::redundant_closure_for_method_calls.\n- Make `match` statements exhaustive; avoid wildcard arms.\n- New traits need doc comments explaining their role and how implementations are expected to behave.\n- No opaque positional `bool`/`Option` parameters (`foo(false)` is unreadable). Prefer enums,\n  named methods, or newtypes. If you must pass an opaque literal by position, use an exact\n  `/*param_name*/` comment matching the callee signature.\n- Prefer native RPITIT trait methods with explicit `Send` bounds\n  (`fn foo(&self) -> impl Future<Output = T> + Send;`) over `#[async_trait]` or\n  `#[allow(async_fn_in_trait)]`. Implementations may use `async fn` when they satisfy the contract.\n- No single-use helper methods. Do not create a helper referenced only once.\n- Instrument async work at the definition (`#[tracing::instrument(...)]`), not with\n  `.instrument(...)` at call sites. Check whether the callee is already instrumented first.\n\n## Change hygiene\n\n- One logical change per PR. Fixes ride with the change that introduced them when possible; a PR\n  that mixes a feature with unrelated lint fixes or refactors hides both from review.\n- If you change dependencies (`Cargo.toml`), regenerate/commit `Cargo.lock` in the same change.\n  A new dependency is an architectural change: state in the PR why the existing crates cannot\n  host the functionality, and `make deny` must stay clean for it.\n- If a change starts forcing edits across many crate internals, stop and fix the boundary instead.\n\n## Tests\n\n- Prefer whole-object equality comparisons over field-by-field checks.\n- Do not add tests for statically defined values.\n- Do not add negative tests for logic that was removed.\n- Bug fixes need a regression test that fails without the fix.\n- Verifiers over self-assessment: tmux user-level tests, differential tests against the TS binary\n  on PATH, golden corpora replayed against real captured data. No lane merges without its verifier\n  passing, rerun by the reviewer where feasible.\n- Tests must wait for observable readiness, not fixed sleeps or retry-to-green loops. If a\n  test must be disabled, give a reason at the test. Use isolated ports and temporary paths, and\n  restore shared state. Run focused tests when changing their behavior.\n\n## Lint discipline\n\n- Zero-warning posture: the merge gates run fmt + clippy + tests at `-D warnings`, so a `warn`\n  lint is a merge blocker. Keep the enabled set deliberate and selective; enable a new lint family\n  only with every current site fixed in the same change.\n- Explain lint exceptions next to the `#[allow(...)]` or workspace configuration; keep\n  exceptions narrow. Advisory ignores in `deny.toml` need a reason and review date.\n\n## Performance and the critical path\n\nThe UI critical path is paint-latency-critical. First paint, and every\nframe the user waits on, must never block on network, disk sync, or\nbackground bookkeeping. The launch benchmarks measure this surface\n(cold/warm ready, first paint); a merge that regresses them undoes the\nproduct's core claim.\n\nRules:\n\n- Nothing user-visible awaits the network. Any HTTP/socket call on a\n  render path (telemetry, catalog fetch, update check) runs on a\n  background worker; the paint path hands the work off and returns\n  immediately. Delivery semantics (timeout, retry, ordering) live with\n  the worker, not the caller.\n- Telemetry is fire-and-forget from user-facing code. `pa-telemetry`'s\n  background worker owns delivery end to end; no startup, session\n  create, tab open, or first-render path may hold a flush or await a\n  sink.\n- Fire-and-forget boundaries need a red-first test: a hanging sink\n  (one that never replies) must not delay paint. The test fails if any\n  await on the critical path reaches the worker's delivery.\n- Tests that mock a sink or run offline cannot prove the above (the\n  benchmark's mock hides the POST). The regression test with a hanging\n  sink is the required verifier.\n\nExample (the #3288 regression this rule exists to prevent): the\ntelemetry startup flush was awaited on the interactive launch path, so\nthe analytics POST — a real HTTPS round-trip, ~157 ms — ran before the\nfirst frame. Every CI check passed because tests set DO_NOT_TRACK=1 and\nthe benchmark mocked the provider offline; only real-network launches\npaid the cost. The fix moved the flush to the background worker and\nadded `the_startup_flush_never_blocks_the_first_frame` (a hanging sink\nmust not delay paint) as the permanent guard. Any change touching the\nlaunch path must keep that test red-first.\n\n\n## Merge gates\n\n- `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`,\n  `cargo test --workspace` must pass before every merge. Run `make check` — the local mirror of\n  the same gates; CI runs on the org's billing (`.github/workflows/continuous.yml` on `main`\n  pushes; `release.yml` on version tags). The PR-only codebase-health check reports growth\n  past 2,000 lines as review guidance; it never blocks a merge.\n- **Parity-diff evidence is a merge gate** (the port's definition, not optional polish): every PR\n  that touches a user-visible surface must include a \"parity-diff evidence\" section in its\n  description showing the TS-binary comparison for what it changed: (1) rendered output —\n  frame-diff vs the TS binary;\n  (2) interactive behavior — the same input handled identically (keys, mouse, timing); \n  (3) wire parity — byte-compare the TS daemon's traffic for protocol changes; (4) user-visible\n  invariants — every user action produces the same visible reaction as TS (`/compact` shows\n  started+completed; `/model` shows the selector; a refinement shows its decoration). A feature\n  that \"works\" but was never diffed against the TS binary does not pass review. If TS shows it,\n  Rust shows it identically; if Rust shows something TS does not, that is also a parity bug.\n- PRs must state ownership compliance (crate README scope/non-goals/public API, dependency\n  direction) and classify the change: internals, new `pub` surface, or a new\n  dependency/cross-crate re-export. The latter two are architectural changes — an innocent-looking\n  `pub use` is a very simple way to break encapsulation.\n- The compiled fallback model catalog `crates/pa-ai/src/models_generated.rs` is\n  hand-maintained Rust mirroring the TS `packages/ai/src/models.generated.ts` object\n  literal — edit it by hand, exactly like its TS source (there is no generator). The\n  parity fixture `crates/pa-models/tests/fixtures/catalog.v1.json` refreshes with\n  `scripts/generate-catalog-fixture.py`. Bulk data files are exempt from the size guidance.\n\n## Adoption telemetry\n\nEvery user-visible feature ships its adoption telemetry event in the same PR as the feature:\nthe event name + properties join the versioned schema (`pa-telemetry`), and a\nseam emits it from day one. Telemetry properties never carry prompt, session, or file content\n(primitives only; see `pa-telemetry`); delivery is fire-and-forget from user-facing code\n(see Performance and the critical path).\n\n## Branding\n\nThe product is Prime Agent - we are not a pi fork. Scrub \"pi\"/\"pi-mono\"/\"pi-ai\"/\n\"Prime Intellect\"-style naming from all user-visible surfaces (docs, READMEs,\nCLI help text, error messages, splash/onboarding strings, keybinding hints, TUI\nlabels, and code comments that quote user-facing strings); brand everything\nPrime Agent. Audit with a repo-wide grep and classify every hit (user-visible\nvs wire-internal vs comment) before scrubbing, and list the preserved wire\nidentifiers in the PR body so the reviewer can verify none were wrongly scrubbed.\n\nEXPLICIT EXCEPTION: wire-protocol identifiers that must stay byte-compatible with the TS product (e.g. the PI_PACKAGE_DIR env var, settings keys, provider IDs like prime-inference, harness _meta namespaces like ai.primeintellect.prime-agent, lockfile names) stay until/unless the TS side renames them — PARITY BEATS BRANDING ON THE WIRE.\n\n\n\n## Surface contract (must not change)\n\n- Tools exposed to the model: `bash`, `edit`, `python_repl` (internal helpers: `rename`, `stdout`).\n- RLM kernel API in the persistent Python REPL: `rlm.spawn/find_models/collect/list_subagents/delete_subagent/create_session/progress_note`, `rlm.harness` CRUD, `agent_message.send`, `agent_observe`, `compact`, `goal`, `refine`, `attach_image`, skills (markdown + Python) per the skill contract in the base system prompt.\n- System prompt structure: layered — cache-stable static layer files (core harness description with the full API surface, mandatory usage rules, opinionated guidelines, per-model additions from the model-prompts TOML rule map) followed by one dynamic tail (packages, project context, skills inventory, MCP servers, environment, session role); the harness digest stays a separate `[harness-digest]` user message. `prime-agent prompt` dumps the assembled prompt with its layer breakdown.\n- CLI shape: `prime-agent` with the same commands/flags as the TS product; headless modes (RPC/daemon/session-worker) with identical behavior.\n\n## Crates\n\nOne owned area per crate; `pa-types` is the only shared vocabulary crate.\nDependencies flow from the composition root toward lower crates, never back upward.\nThe table summarizes each crate's current direct workspace dependencies:\n\n| Crate | Purpose | Direct workspace dependencies |\n| --- | --- | --- |\n| `pa-types` | Shared wire and domain types | none |\n| `pa-telemetry` | Events and sinks | none |\n| `pa-agent` | Provider-independent agent loop | none |\n| `pa-ai` | Providers, model registry, streaming | `pa-types` |\n| `pa-models` | Live model catalog and transport | `pa-ai`, `pa-types` |\n| `pa-core` | Session engine, tools, skills, kernel, settings | `pa-types`, `pa-ai`, `pa-models`, `pa-agent`, `pa-telemetry` |\n| `pa-daemon` | Supervisor, workers, wire protocol | `pa-types`, `pa-core`, `pa-agent`, `pa-ai`, `pa-telemetry`, `pa-models` |\n| `pa-tui` | Terminal UI, daemon-wire client | `pa-types` |\n| `pa-cli` | `prime-agent` binary, composition root | `pa-types`, `pa-core`, `pa-ai`, `pa-agent`, `pa-daemon`, `pa-tui`, `pa-telemetry` |\n| `pa-perf` | Performance corpora + pty bench harness (dev/CI tooling, never shipped) | `pa-types`, `pa-core`, `pa-daemon` |\n\nLayering rules:\n\n- Dependencies only point from higher crates to lower crates shown above. No cycles or\n  reverse edges. The leaf crates are peers; add only the dependencies needed for their work.\n  Shared wire/domain vocabulary belongs in `pa-types`, not in a higher crate or a duplicate.\n- `pa-tui` renders from wire types and events; it does not link the session engine.\n- `pa-cli` is a composition root: it wires crates together and contains no business logic.\n\n## Reliability model\n\n- The daemon is a supervisor: it spawns one worker process per active session instead of hosting sessions in-process. Workers are supervised, restarted with backoff, and sessions persist on disk (append-only JSONL, same layout as `~/.prime/agent/sessions`) so reattach works even if the supervisor restarts.\n- No stubs, no `todo!()`, no swallowed errors (`anyhow` bubbling to UI is fine).\n\n## References\n\n- Cursor Bugbot's PR review rules (`.cursor/BUGBOT.md`) mirror the standards in this file - update both whenever either changes.\n","skills/agent-message/SKILL.md":"---\nname: agent-message\ndescription: Message an agent's parent, siblings, or direct children through the daemon. Discover reachable agents with agent_observe.list_agents, then send direct text without spoofing sender identity.\n---\n\n# Agent Message\n\nSend direct messages within the current agent's nuclear family through the\nlocal daemon: parent, siblings, and direct children only. Roots are siblings.\nThe daemon derives your sender identity from the current session; do not try\nto include a `from` field.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    receipt = await agent_message.send(\n        \"Please inspect the latest result.\",\n        receiver_role=\"child\",\n        receiver_name=child.session_name,\n    )\n    # Keep the child until this follow-up finishes so its result remains observable.\n```\n\n## API\n\n- `await agent_observe.list_agents()` (agent-observe skill) is the roster: it\n  lists the parent, siblings, and children this skill can reach, active or not,\n  with the `relationship` and `sessionName` that `send` takes as\n  `receiver_role` and `receiver_name`.\n- `await agent_message.send(message, receiver_role=\"parent\" | \"sibling\" | \"child\", receiver_name=None)` — sends one direct\n  text message to one family member. Sending to an inactive or idle completed\n  subagent wakes it and starts an ordinary follow-up turn in that same session\n  and context.\n  The child remains available only until its parent session closes. The daemon\n  resolves `receiver_role` within the current agent family; `receiver_name` is\n  required for siblings and children and omitted for the unique parent.\n  `send(\"all\", message)` broadcasts only to the family roster and returns\n  `{receipts: [...]}` in roster order; successful entries are ordinary receipts\n  and failed entries contain the target id and a short `error`. One failed delivery\n  does not reject successful deliveries. Messages always use steering delivery so\n  a busy target sees them during its active run. Returns a receipt with a\n  `deliveryStatus` field: `\"delivered\"` means the message reached an idle target's\n  context; `\"queued\"` means a steering message was accepted and will deliver when\n  the target's current work allows (`send` does not block waiting for that).\n  Delivered receipts carry `deliveredAt`, queued receipts carry `queuedAt`.\n\n## Safety\n\n- Do not delete a child immediately after `send`: delivered follow-ups may still\n  be running and queued receipts have not run yet. Wait until observation shows\n  the child is idle and its context is no longer needed before calling\n  `await rlm.delete_subagent(child)`.\n- Reach is limited to parent, siblings, and direct children; relay through an\n  intermediate child instead of messaging grandchildren or cousins directly.\n- Sender identity is daemon-derived and cannot be spoofed from Python.\n- The daemon enforces message size, rate, and pending-queue limits before\n  accepting delivery.\n","skills/agent-observe/SKILL.md":"---\nname: agent-observe\ndescription: Read-only roster and observation of an agent's parent, siblings, and direct children. Use to discover reachable agents and to inspect family status and bounded recent-message previews without mutating sessions.\n---\n\n# Agent Observe\n\nObserve the current agent's nuclear family through the local daemon: parent,\nsiblings, direct children, and self. `list_agents` is the one family roster and\ncovers every member `agent_message.send` can reach. `get_agent` also returns an\ninactive child's roster row. `recent_messages` reads live sessions only; it\ndoes not rehydrate an inactive member. They cannot read a root sibling that has\nno live session in this worker.\nThis skill is read-only: it can list family sessions, inspect one session, and fetch\nbounded recent message previews. It cannot prompt, steer, clear, kill, rename, or\notherwise mutate another session.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    worker = await agent_observe.get_agent(child.session_name)\n    recent = await agent_observe.recent_messages(child.session_name, limit=6)\n    # Deletion is a parent-owned RLM operation, not an observe mutation:\n    await rlm.delete_subagent(child)\n```\n\n## API\n\n- `await agent_observe.list_agents()` returns `current` (the calling agent's\n  own row) and `agents` (the family: parent, siblings, and direct children,\n  active or not; the caller is excluded from `agents`). Each row carries\n  `sessionId`, optional `sessionName`, `relationship`\n  (`parent`/`sibling`/`child`), `status` (`running`/`idle` for live sessions,\n  `inactive` without one), the live `activity` (`tool`/`model`/`compacting`/\n  `busy`/`user`/`idle`), `isSessionActive`, the counts known\n  for it (`messageCount`, `queuedCount`, `attachedClients`), `cwd` when the\n  roster row carries it, the parent edges (`parentActiveSessionId`,\n  `parentSessionId`) and `rlmChildId` for subagents, and `firstMessage`\n  (capped at 240 chars) for an inactive child. A member with no live session\n  has no `activeSessionId` and no live detail; address it with\n  `agent_message.send` using its `relationship` plus its `sessionName`, or its\n  `sessionId` when the member has no name. For direct children,\n  `await rlm.list_subagents()` also exposes parent-owned lifecycle handles.\n- `await agent_observe.get_agent(target)` returns `agent`, where `agent`\n  contains one agent summary (the same shape as the roster rows, including a\n  passive child's row). `target` is resolved like other live-session\n  selectors: active id, session id or name, or an unambiguous id suffix.\n- `await agent_observe.recent_messages(target, limit=8, max_chars=800)`\n  returns `agent` (the target's summary), `messages` (up to `limit` recent\n  bounded previews), the clamped `limit` and `maxChars`, and `truncated`\n  (true when older messages exist beyond the returned window). `limit` must be\n  1-50, and `max_chars` must be 80-2000. The target must be a live family\n  member: a member with no live session errors instead of hydrating.\n\n## Safety\n\n- This skill is read-only and exposes no mutation commands.\n- Targets outside the nuclear family are rejected; transcript reads follow the\n  same family rule as messaging.\n- Message access is bounded by count and per-message character limit.\n- Prefer status and recent previews for orchestration. Ask the user before\n  using observed context to steer or message another session.\n","skills/attach-image/SKILL.md":"---\nname: attach-image\ndescription: Load an on-disk image (PNG, JPEG, GIF, WebP) into the model's context as a viewable attachment so the model can directly SEE it — for screenshots, diagrams, charts, photos, or scanned pages. Use this when you need to perceive an image's visual contents. Requires a vision-capable model; errors clearly otherwise.\n---\n\n# Attach Image\n\nLoad on-disk images into the model's context as multimodal attachments. The\nimage is sent to the model the same way a pasted image is, so the model can\nactually look at it.\n\n## When to use this\n\n- The user points at an image file and wants you to look at it.\n- You need to read text, a chart, a diagram, or a layout from an image.\n- A screenshot needs visual interpretation.\n\n## When NOT to use this\n\nFor *programmatic* work on an image — measuring pixels, cropping, resizing,\ncomputing a hash, comparing files byte-by-byte — open it in the kernel with a\nlibrary instead:\n\n```python\nfrom PIL import Image\nimg = Image.open(\"diagram.png\")\nprint(img.size)\n```\n\nThat path does not put the image in the model's context; it only lets you\ncompute over it. Use `attach_image` when you need to *see* the image.\n\n## Usage\n\nCall the prepared `attach_image` import directly in the Python kernel:\n\n```python\nprint(await attach_image(\"diagram.png\"))\nprint(await attach_image(\"a.png\", \"b.jpg\"))\n```\n\nThe skill automatically resizes and compresses large images before loading them\ninto context. Animated images that need compression are flattened to their first\nframe. Transparent images that need compression are composited onto a neutral\ngray background. Extremely large images are rejected by pixel count before full\nprocessing. The original file is left untouched.\n\nSupported formats: PNG, JPEG, GIF, WebP. The skill errors if a file is not a\nsupported image, or if the current model is not vision-capable.\n","skills/compact/SKILL.md":"---\nname: compact\ndescription: Check context usage and compact the conversation from the Python REPL. Use when context is filling up and substantial work remains, so the session is summarized and you keep working instead of stopping early.\n---\n\n# Compact\n\nCompaction replaces older conversation history with a dense summary, freeing\ncontext so long-running work can continue. The implementation lives in the\nhost (the same one behind the user's `/compact` command); this skill is the\nkernel-side interface to it. Call it directly from the Python REPL:\n\n```python\nawait compact.status()\nawait compact.run()\nawait compact.run(\"keep the failing test names and the migration checklist\")\n```\n\n## API\n\n- `await compact.status()` — current context usage as a dict: `tokens`,\n  `context_window`, and `percent` (`None` right after a compaction until the\n  next model response), plus `scheduled` (whether a requested compaction is\n  already pending).\n- `await compact.run(instructions=None)` — schedule compaction. Returns\n  `{\"scheduled\": True}`, or `{\"scheduled\": False, \"reason\": ...}` when there\n  is nothing to compact yet. Optional `instructions` focus the summary on\n  what matters for the remaining work.\n\n## Rules\n\n- Compaction never runs mid-cell. A scheduled compaction runs when the\n  current turn ends; the harness then resumes you automatically with the\n  summary plus recent messages, and you continue the task.\n- The Python kernel persists through compaction — variables, imports, and\n  helpers you defined all remain available.\n- Compact at a natural boundary when context usage is high and substantial\n  work remains, instead of becoming terse or returning to the user early.\n  Check `await compact.status()` when unsure.\n- One request per turn is enough; calling `run` again before the turn ends\n  only updates the instructions.\n","skills/edit/SKILL.md":"---\nname: edit\ndescription: Replace an exact, unique string in an existing file. Use for targeted single-occurrence edits to files from the Python kernel instead of rewriting the whole file.\n---\n\n# Edit\n\nMake a targeted edit to an existing file by replacing one exact, unique\noccurrence of a string. `old_str` must appear exactly once in the file.\n\nCall directly from the kernel:\n\n    await edit(path=\"pkg/file.py\", old_str=old, new_str=new)\n\nUse exact old/new strings. If the text contains triple double quotes, use\ntriple single-quoted variables (`old = '''...'''`) or build `old`/`new` from\ninspected file slices. Returns a short confirmation; raises if `old_str` is\nmissing or matches more than once (widen the snippet to make it unique).\n\nOr from a shell cell:\n\n    !edit --path pkg/file.py --old-str \"...\" --new-str \"...\"\n","skills/factory/SKILL.md":"---\nname: factory\ndescription: Run state-machine workflows of spawned child agents: store a validated machine or dag spec as a continual-harness factory entry (rlm.harness.create_factory), then run, watch, stop, and resume it through rlm.factory. For the full authoring reference and API guide, call rlm.factory.help() in the kernel.\n---\n\n# Factory\n\nThe factory runs state-machine workflows of spawned child agents. A stored\nfactory entry — harness kind `factory`, written with\n`rlm.harness.create_factory` — declares the machine: states, each backed by\na subagent spec, plus guarded transitions between them. The spec validates\nat write time (machine form, or `dag` sugar that compiles to one; pass\nexactly one), and an invalid spec is never stored.\n`await rlm.factory.run('<spec_id>')` then spawns each state's subagent as an\nordinary child, feeds captured outputs into the successors' prompts, and\ndrives the run to quiescence in a background kernel task — the call\nreturns immediately and the run continues after the model turn ends. Use\nit when a workflow needs shape: fan-out, bounded loops (review/fix until a\nverdict approves), joins, or one child per list item.\n\n**For the full authoring reference and API guide — states, ports, guards,\njoins, foreach, residents, budgets and policies, and the `rlm.factory`\nrun/status/stop/resume/graph/watch calls with worked examples — call\n`rlm.factory.help()` in the kernel.** The guide lands with the factory-core\nPR; on builds without it, the module docstring in\n`prime-agent-runtime/src/rlm/factory.py` is the source of truth.\n\n## The opt-in gate\n\nThe factory ships disabled. `rlm.factory.help()` answers while it is off\n(the authoring guide stays readable before opting in), but every other\n`rlm.factory` call and every factory harness write refuses with one\nmessage: `the factory is disabled; run /factory on to enable it`. The\nuser turns it on with `/factory on` in the client (`/factory off`\ndisables it again — refused while the session still has live runs, and\non a lane-advertising client while the live-run count cannot be read, so\nan active factory never loses its stop path, `/factory status` reports\nit), which persists the\n`factory.enabled` setting in the agent dir's settings.json — the same\nsetting the daemon's `factory_activity` lane advertisement reads, so the\nTUI's factory dock group and page surface only on a client started while\nthe factory is enabled. If a call refuses with that message, tell the\nuser to run `/factory on` and restart the client.\n\n## Discovering machines\n\n- The machine library: machines are `MACHINE.md` files, one directory\n  per machine — the bundled seeds ship inside the runtime package (wheel\n  package data, `rlm/machines/<name>/MACHINE.md`; `PRIME_AGENT_MACHINES_DIR`\n  redirects that level at a team directory), and the personal library\n  lives under the agent dir. `prime-agent factory list | import | export`\n  manages them. The seeds are `builder`, `pr-manager`, and `review-sweep`.\n- The TUI factory page: the activity dock's `⚙ N factory` group (Enter or\n  click) opens one live diagram per run, newest run first. The up/down\n  arrows move the selection, Enter opens the selected run's action rows\n  (stop, or resume while it is paused — arrows to walk, Enter to run),\n  Esc closes.\n","skills/goal/SKILL.md":"---\nname: goal\ndescription: Manage the persistent thread goal from the Python REPL. Use to read goal status and budget usage, to start a goal when the user explicitly asks for one, or to mark the active goal complete once its objective is fully achieved.\n---\n\n# Goal\n\nThe thread goal is a persistent objective the harness keeps re-prompting you to\npursue across turns until it is complete. Goal state (status, token budget,\nusage accounting) lives in the host; this skill is the kernel-side interface to\nit. Call it directly from the Python REPL:\n\n```python\nawait goal.get()\nawait goal.create(\"ship the release notes\")\n# Only pass token_budget when the user explicitly asks for one:\n# await goal.create(\"ship the release notes\", token_budget=200000)\nawait goal.complete()\n```\n\n## API\n\n- `await goal.get()` — current goal as a dict: `goal` (or `None` when no goal\n  is set), `remaining_tokens`, and `completion_budget_report`. The `goal` dict\n  carries `objective`, `status`, `token_budget`, `tokens_used`,\n  `time_used_seconds`, and timestamps.\n- `await goal.create(objective, token_budget=None)` — start a new active goal.\n  Fails while a goal is still pending (active, paused, or budget-limited); a\n  completed or errored goal is replaced by the new one. Only create a goal when\n  the user or system/developer instructions explicitly ask for a persistent\n  long-running goal; do not infer goals from ordinary tasks. Set `token_budget`\n  only when an explicit token budget is requested.\n- `await goal.complete()` — mark the existing goal achieved. Use only when the\n  objective has actually been achieved and no required work remains; do not\n  call it merely because the budget is nearly exhausted or because you are\n  stopping work. When the result includes a `completion_budget_report`, report\n  that final usage to the user.\n\n## Rules\n\n- Goal status transitions other than completion (pause, resume, clear,\n  budget-limiting) are controlled by the user and the host; there is no API for\n  them here.\n- When an active goal is actually complete, call `await goal.complete()`; do\n  not merely say it is done — the harness keeps continuing the goal until the\n  completion call arrives.\n","skills/mcp/SKILL.md":"---\nname: mcp\ndescription: Use external MCP services generically from Python - search the supported-service catalog, inspect the user's connections, discover live tool schemas, and call tools on any connection (Notion, Linear, Slack, and the rest of the catalog) without per-service packages.\n---\n\n# MCP Services\n\nEvery external service reachable over MCP uses the same pre-imported `mcp`\nmodule. Adding a service is data (a catalog entry plus a user login), never a\nnew Python package, and there are no per-service skills to read.\n\n## Inventory: what can I use?\n\n```python\n# Supported catalog, one bounded page. More pages exist while nextCursor is not None.\npage = await mcp.list_plugins(connection_status=\"not_connected\", limit=50)\nresults = await mcp.search_plugins(\"notion\")          # bounded search\npage = await mcp.list_plugins()                       # default: first 50 entries\n\n# The user's actual connections. connectionId is the dispatch id everywhere below.\nconnections = await mcp.list_connections()\n```\n\nCatalog entries carry `connectionStatus` (`connected`, `pending`,\n`not_connected`, `setup_required`, `disabled`, `error`), `connectable`, and\nwhen connected the `connectionIds` you dispatch on. `connected` means a\nverified MCP handshake, not just stored credentials; `pending` means\ncredentials exist but verification hasn't run or succeeded yet. Entries may\nalso carry `setupHint` (why a service isn't connectable yet), `unverified`\n(imported but not vetted), `verifiedAt`/`toolCount`, and `connectionIds`\n(empty when not dispatchable). Entries with `setup_required` need a developer\napp or API key first — say so honestly instead of promising one-click.\n\n## Recommend, never connect\n\nIf a task would benefit from an unconnected service, name the real catalog\nentry (e.g. \"Connecting Notion would let me search your workspace directly\")\nand tell the user to open `/plugins` (or run `/mcp login <service>`) to connect.\nRecommendations and catalog lookups never install anything, open a browser,\nuse credentials, or request extra scopes. There is no agent-initiated connect\ncall in this slice; if the user connects mid-task, the connection activates on\nthe next call without a reload.\n\n## Discover, then call\n\n```python\n# Live tool metadata is cached per connection; schemas come from the server.\ntools = await mcp.search_tools(\"search workspace documents\", connection_id=\"notion\")\ntool = await mcp.describe_tool(\"notion\", \"notion-search\")   # {name, description, inputSchema}\ntools = await mcp.list_tools(\"notion\")                     # full tool list with schemas\n\nresult = await mcp.call_tool(\"notion\", \"notion-search\", {\"query\": \"roadmap\"})\n```\n\n- Discover before calling: don't assume tool names or arguments; read the\n  `inputSchema` with `describe_tool` and construct matching arguments.\n- `list_tools` returns the complete inventory or raises — never a silent\n  partial list. Returned schemas are isolated copies; mutate them freely.\n- `search_tools` without a `connection_id` searches at most 8 connections the\n  host reports as connected and reports its scope: `searched`, `unavailable`\n  (per-connection failures as fixed, redaction-safe summaries), and\n  `truncated` (narrow the query or pick a connection when it is set — the\n  result never claims to be exhaustive).\n- Prefer narrow catalog searches over paging the whole catalog; don't dump all\n  schemas into context.\n- Results are already-parsed Python (a `dict` for structured output, otherwise\n  a string). No `json.loads` needed.\n\n## Errors and permissions\n\n- `PermissionError` — the tool is excluded by the user's `enabledTools` /\n  `disabledTools` policy. Don't retry; tell the user.\n- `KeyError` — the tool or connection doesn't exist. Re-check with\n  `list_tools` / `list_connections`; tools can change across sessions.\n- `McpDiscoveryError` — the server's tool listing couldn't complete honestly\n  (broken pagination). No partial inventory is published; re-run, and ask the\n  user to reconnect if it persists.\n- `RuntimeError` — credentials are not available (`McpCredentialsUnavailable`:\n  ask the user to connect via `/plugins` or `/mcp login <service>`, never via\n  environment variables), a refresh failed, or the host bridge is unavailable.\n- `McpToolError` — the server flagged the call as an error. Surface the\n  message; don't blindly retry a write that may have already happened.\n\nCredentials never appear in inventory results, tool schemas, or errors.\n","skills/prime-intellect/SKILL.md":"---\nname: prime-intellect\ndescription: Work with Prime Intellect products via the prime CLI and Python SDKs - verifiers environments and the Environments Hub, evaluations (local and hosted), Hosted Training and prime-rl, code sandboxes, Prime Inference, GPU compute (pods and clusters), storage, and tunnels. Use when a task involves Prime Intellect, the prime CLI, verifiers, RL environments, evals, training, sandboxes, renting GPUs, Prime Inference models, or when the user asks what Prime Intellect is or what it offers.\n---\n\n# Prime Intellect\n\nPrime Intellect is an open superintelligence lab building open-source AGI infrastructure: a platform for RL environments, evaluations, post-training, inference, and globally distributed GPU compute. Prime Agent (this agent) is built by Prime Intellect, and the `prime` CLI is the default way to interface with every product below.\n\n## Product Map\n\n| Product | What it is | Details |\n|---|---|---|\n| verifiers | Python library for building LLM environments and evaluations | [environments.md](references/environments.md) |\n| Environments Hub | Platform library of community RL environments (`prime env`) | [environments.md](references/environments.md) |\n| Hosted Evaluations | Run evals on Prime-managed infra (`prime eval run --hosted`) | [environments.md](references/environments.md) |\n| Hosted Training | Post-train models against environments (`prime train`, Lab) | [environments.md](references/environments.md) |\n| prime-rl | Large-scale async RL framework for self-managed training | [environments.md](references/environments.md) |\n| Sandboxes | Secure disposable VM sandboxes for AI-generated code | [sandboxes.md](references/sandboxes.md) |\n| Tunnels | Public HTTPS URLs for local/sandboxed services | [sandboxes.md](references/sandboxes.md) |\n| Inference | OpenAI-compatible API for frontier models | [inference.md](references/inference.md) |\n| Compute | Rent single GPU pods or multi-node clusters | [compute.md](references/compute.md) |\n| Storage | Persistent disks shared between instances | [compute.md](references/compute.md) |\n\n## Prime CLI Setup\n\nDefault to the `prime` CLI for all Prime Intellect operations. If it is not installed:\n\n```bash\nuv tool install prime    # or: pip install prime\nprime login              # browser auth; or: prime config set-api-key\nprime config view        # verify configuration\n```\n\nThe same package provides the Python SDKs (e.g. `prime_sandboxes`, `prime_tunnel`). Source: https://github.com/PrimeIntellect-ai/prime\n\n## Live Documentation\n\nAuthoritative, current docs live at https://docs.primeintellect.ai. Any docs page is fetchable as Markdown by appending `.md` to its URL, and the full index is at https://docs.primeintellect.ai/llms.txt. When you need details not covered here (exact flags, API schemas, pricing, new features), fetch the live docs instead of guessing:\n\n```bash\ncurl -s https://docs.primeintellect.ai/llms.txt                      # discover pages\ncurl -s https://docs.primeintellect.ai/sandboxes/overview.md         # fetch a page as markdown\n```\n\nThe REST API is documented under `api-reference/` pages (OpenAPI spec: https://api.primeintellect.ai/openapi.json), with `https://api.primeintellect.ai` as the base URL.\n\n## Command Quick Reference\n\n```bash\n# Environments Hub\nprime env list --search \"math\"      # discover environments\nprime env info owner/name           # inspect one\nprime env install owner/name        # install locally\nprime env init my-env --v1          # scaffold a new environment\nprime env push                      # publish to the Hub\n\n# Evaluations\nprime eval run my-env -m openai/gpt-4.1-mini -n 5    # local smoke eval\nprime eval run owner/env --hosted --follow           # hosted eval with logs\n\n# Training\nprime lab setup                     # set up a Lab workspace (Hosted Training)\nprime train models                  # models, capacity, pricing\nprime train init && prime train rl.toml              # configure + launch a run\n\n# Sandboxes\nprime sandbox create python:3.11-slim --timeout-minutes 120\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox delete <sandbox-id>\n\n# Inference\nprime inference models              # list available models\n\n# Compute\nprime availability list             # GPU availability + pricing\nprime pods create                   # provision a pod\nprime pods ssh <pod-id>             # SSH in (needs: prime config set-ssh-key-path)\n```\n\n## Working Conventions\n\n- Prefer ecosystem-native paths (`prime env init`, `prime eval run`, `prime lab setup`) over custom scaffolding.\n- Smoke-test small (`-n 5`) before scaling evals or training; keep default result uploads unless the user explicitly opts out.\n- For non-trivial eval/training work, ask whether the user wants instruct models (`gpt-4.1` series, `qwen3` instruct) or reasoning models (`gpt-5` series, `qwen3` thinking, `glm` series).\n- Hosted Training launches from a CPU machine; self-managed `prime-rl` requires local GPU access and is a power-user path.\n- The dashboard at https://app.primeintellect.ai covers API keys, billing, teams, and anything the CLI does not.\n","skills/prime-intellect/references/compute.md":"# Compute & Storage\n\nPrime Intellect aggregates GPU capacity across providers: rent single GPU pods on demand or deploy multi-node clusters, with persistent network-attached storage.\n\nLive docs: `cli-reference/check-gpu-availability.md`, `cli-reference/provision-gpu.md`, `cli-reference/managing-disks.md`, `tutorials-multi-node-cluster/deploy-multi-node.md`, `tutorials-storage/create-persistent-storage.md` under https://docs.primeintellect.ai/\n\n## GPU Availability\n\n```bash\nprime availability list                        # all GPUs with pricing\nprime availability list --gpu-type H100_80GB   # filter by GPU type\n```\n\n## Pods (single instances)\n\n```bash\nprime config set-ssh-key-path   # one-time: SSH key for pod access (generate on the dashboard profile page)\nprime pods create               # interactive provisioning from availability data\nprime pods list\nprime pods ssh <pod-id>\n```\n\nPods support custom Docker images (`tutorials-on-demand-cloud/deploy-custom-docker-image.md`). Monitor, terminate, and inspect pods from the CLI or the dashboard.\n\n## Multi-Node Clusters\n\nDeploy multi-node clusters (with optional Slurm orchestration) from the platform; see `tutorials-multi-node-cluster/deploy-multi-node.md` and `tutorials-multi-node-cluster/slurm-orchestration.md`. Cluster monitoring guidance lives at `tutorials-reserved-clusters/monitoring.md`.\n\n## Storage\n\nPersistent disks outlive individual instances and can be attached to different instances as needed:\n\n- Create disks from the Storage tab of the Instances page (choose provider, datacenter, size), then attach them to pods or clusters.\n- Manage disks from the CLI as well — see `cli-reference/managing-disks.md`.\n- For multi-node shared and ephemeral storage patterns, see `tutorials-storage/cluster-storage.md`.\n\n## Teams\n\nManage team membership and run resources against team billing:\n\n```bash\nprime teams list\n```\n\nMost provisioning commands accept a `--team-id` flag; the REST API equivalent is the `X-Prime-Team-ID` header.\n","skills/prime-intellect/references/environments.md":"# Environments, Evaluations & Training\n\nverifiers is Prime Intellect's Python library for LLM environments: packages that expose `load_environment` and bundle datasets, rollout logic, and reward rubrics. Environments power evaluations (local and hosted) and RL training (Hosted Training or self-managed prime-rl).\n\nLive docs: `verifiers/overview.md`, `tutorials-environments/getting-started.md`, `hosted-training/getting-started.md`, `prime-rl/overview.md` under https://docs.primeintellect.ai/ (append `.md` for raw markdown). Source: https://github.com/PrimeIntellect-ai/verifiers and https://github.com/PrimeIntellect-ai/prime-rl\n\n## Discovering Environments (Hub)\n\n```bash\nprime env list --search \"math\" --owner primeintellect --show-actions\nprime env list --tag tools --tag sandbox\nprime env list --mine\nprime env list --starred\nprime env info owner/name        # metadata, version, dependencies\nprime env status owner/name      # CI/action status\nprime env pull owner/name -t ./tmp-env   # pull source for inspection\nprime env install owner/name     # install locally\n```\n\nWhen picking candidates, prefer: `primeintellect`-owned, passing latest actions, updated within ~2 months, recent verifiers versions. Compare task type (single-turn, multi-turn, tool, sandbox, agent), reward type (binary, continuous, judge-based), and dependency/secret requirements.\n\n## Creating Environments\n\n```bash\nprime env init my-env --v1       # scaffold (add --with-harness for an explicit reusable harness)\nprime env install my-env\nprime eval run my-env -m openai/gpt-4.1-mini -n 5   # smoke test immediately\nprime env push                   # publish to the Hub\n```\n\nBuild guidance:\n\n- Define the task contract first: prompt shape, allowed tools, stop conditions, rubric outputs, metrics.\n- Prefer starting from an existing Hub environment (`prime env list --search`, then `prime env install owner/name`) over building from scratch.\n- v1 environments expose `load_environment(config: vf.EnvConfig) -> vf.Env`; Taskset + Harness environments additionally expose `load_taskset(config)` and optionally `load_harness(config)` with `load_environment` delegating through `vf.load_taskset`/`vf.load_harness`.\n- The environment must install, load, evaluate, and train without hidden setup.\n\n## Evaluations\n\n`prime eval run` is the canonical eval path. Runs save automatically (visible in the Evaluations tab and `prime eval view`); do not add `--skip-upload` unless the user explicitly asks.\n\n```bash\nprime eval run my-env -m openai/gpt-4.1-mini -n 5               # smoke\nprime eval run owner/env -m openai/gpt-4.1-mini -n 200 -r 3 --shuffle -s   # scaled\nprime eval run owner/env --hosted --follow                       # hosted, streaming logs\n```\n\n- Smoke-test first; scale only after a pass. Use `--shuffle` (seed defaults to 0; set `--shuffle-seed` for reproducible reports).\n- Hosted evals require the environment to be published (`prime env push`) and support TOML configs and temporary sandbox/tunnel permissions (`--allow-tunnel-access`).\n- Prime Inference models include estimated run cost in eval output automatically.\n- Keep reusable model endpoints as aliases in `configs/endpoints.toml` (fields: `endpoint_id`, `model`, `url`, key) and reference them with `-m <endpoint_id>`.\n\n## Training\n\nDefault to Hosted Training unless the user explicitly wants self-managed infrastructure.\n\n```bash\nprime lab setup                  # Lab workspace for environments, evals, GEPA, Hosted Training\nprime train models               # supported models, capacity, pricing\nprime train init                 # generate a training config\nprime train rl.toml              # launch the run\n```\n\n- Hosted Training launches from a CPU machine; no local GPUs needed.\n- Validate the environment with an eval before training (e.g. `-n 20 -r 3 -s`) and confirm reward diversity exists at baseline.\n- Self-managed path: `prime lab setup --prime-rl`, then follow prime-rl's own configs and launch commands. Treat prime-rl as a power-user path requiring local GPU access; see https://docs.primeintellect.ai/prime-rl/overview.md.\n\n## Model Family Choice\n\nAsk the user whether they want instruct or reasoning models before non-trivial runs:\n\n- Instruct (quick behavior checks): `gpt-4.1` series, `qwen3` instruct series.\n- Reasoning (harder probes, deeper coverage): `gpt-5` series, `qwen3` thinking series, `glm` series.\n","skills/prime-intellect/references/inference.md":"# Prime Inference\n\nPrime Inference is an OpenAI-compatible API for frontier and open models, routed across providers and built for large-scale evaluations.\n\nLive docs: `inference/overview.md`, `inference/usage.md`, `inference/adapter-deployments.md`, `inference/troubleshooting.md` under https://docs.primeintellect.ai/\n\n## Setup\n\n1. Create an API key on https://app.primeintellect.ai (account settings → API Keys) with the **Inference** permission enabled — without it, requests fail with authentication errors.\n2. Export it:\n\n```bash\nexport PRIME_API_KEY=\"your-api-key-here\"\n```\n\n## Via the CLI (recommended for evaluations)\n\n```bash\nprime inference models                                   # list available models\nprime eval run gsm8k -m meta-llama/llama-3.1-70b-instruct -n 25   # evals route through Prime Inference\n```\n\nEval runs against Prime Inference models report estimated USD cost automatically.\n\n## Direct API (OpenAI-compatible)\n\nBase URL: `https://api.pinference.ai/api/v1`\n\n```python\nimport openai, os\n\nclient = openai.OpenAI(\n    api_key=os.environ[\"PRIME_API_KEY\"],\n    base_url=\"https://api.pinference.ai/api/v1\",\n)\nresponse = client.chat.completions.create(\n    model=\"meta-llama/llama-3.1-70b-instruct\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n```\n\nAnything that speaks the OpenAI API works — just point it at the base URL above. Streaming and advanced parameters are covered in `inference/usage.md`.\n\n## Teams & Adapters\n\n- Team billing: send the `X-Prime-Team-ID` header (find the ID via `prime teams list` or the Team Profile page) to use team credits instead of personal balance.\n- LoRA adapters trained with Hosted Training can be deployed and queried through the same OpenAI-compatible API (`inference/adapter-deployments.md`).\n","skills/prime-intellect/references/sandboxes.md":"# Sandboxes & Tunnels\n\nPrime Sandboxes are disposable VM environments for running AI-generated or untrusted code in the cloud: isolated, fast to create, billed only while running (CPU $0.05/core/hr, memory $0.01/GB/hr, disk $0.001/GB/hr).\n\nLive docs: `sandboxes/overview.md`, `sandboxes/cli.md`, `sandboxes/sdk.md`, `sandboxes/images.md`, `sandboxes/tunnel.md` under https://docs.primeintellect.ai/\n\n## CLI Lifecycle\n\n```bash\nprime sandbox create python:3.11-slim --timeout-minutes 120   # any Docker image\nprime sandbox list\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox get <sandbox-id>\nprime sandbox delete <sandbox-id>\n```\n\nUseful create flags:\n\n```bash\nprime sandbox create python:3.11-slim \\\n  --name analytics-lab \\\n  --cpu-cores 2 --memory-gb 4 --disk-size-gb 20 \\\n  --timeout-minutes 240 \\\n  --idle-timeout-minutes 15 \\\n  --env APP_ENV=staging \\\n  --secret API_KEY=sk-abc123 \\\n  --yes\n```\n\n- `--timeout-minutes` caps total lifetime; `--idle-timeout-minutes` reaps the sandbox early when no exec/upload/download/file-read arrives (1 ≤ idle ≤ timeout ≤ 1440; for VM sandboxes, `timeout_minutes` may be negative to disable the lifetime deadline).\n- `--env` values are plain text; `--secret` values are encrypted at rest and obfuscated in output. Both become environment variables inside the sandbox.\n- Default start command keeps the sandbox idle, ready for `prime sandbox run`. To run your own process at boot, pass the command after `--` as separate tokens (no shell): `prime sandbox create python:3.11-slim -- python serve.py --port 8000`.\n- Outbound internet is on by default; restrict egress with network allow/deny lists (`prime sandbox network`, or `network_allowlist`/`network_denylist` in the SDK).\n- `--team-id` bills a team; `--yes` skips confirmation in automation.\n\nCustom images: build and push your own via Prime Images (`sandboxes/images.md`).\n\n## Python SDK\n\n`prime_sandboxes` ships `SandboxClient` (sync) and `AsyncSandboxClient` (async) with identical methods:\n\n```python\nfrom prime_sandboxes import SandboxClient, CreateSandboxRequest, APIClient\n\nclient = SandboxClient(APIClient())\nsandbox = client.create(CreateSandboxRequest(\n    name=\"sdk-demo\",\n    docker_image=\"python:3.11-slim\",\n    timeout_minutes=120,\n    environment_vars={\"LOG_LEVEL\": \"debug\"},\n    secrets={\"API_KEY\": \"sk-abc123\"},\n))\nclient.wait_for_creation(sandbox.id)\nresult = client.execute_command(sandbox.id, \"python -c 'print(42)'\")\nclient.upload_file(sandbox.id, \"/workspace/data.csv\", \"./data.csv\")\nclient.download_file(sandbox.id, \"/workspace/output.csv\", \"./output.csv\")\nclient.delete(sandbox.id)\n```\n\nAsync variant: `async with AsyncSandboxClient() as sandboxes: await sandboxes.create(...)` — same methods, useful for fanning out many sandboxes concurrently.\n\n## Tunnels\n\nPrime Tunnel exposes a local (or in-sandbox) service through a secure public HTTPS URL — for dev servers, webhooks, and sharing work in progress:\n\n```python\nfrom prime_tunnel import Tunnel\n\ntunnel = Tunnel(local_port=8000)\nawait tunnel.start()   # prints the public URL\n```\n\nHosted evaluations can create tunnels too: launch the run with `--allow-tunnel-access` (grants tunnel permission to the temporary `PRIME_API_KEY`), then use the same flow inside the hosted sandbox.\n","skills/refine/SKILL.md":"---\nname: refine\ndescription: Trigger continual harness refinement from the Python REPL. Use when you notice a repeated failure, reusable tactic, delegation role, or behavior policy that should be persisted as a harness entry. Returns immediately; refinement runs when the current turn ends.\n---\n\n# Refine\n\nRefinement analyzes the conversation trajectory and applies small, evidence-backed\nupdates to the continual harness (prompts, memories, skills, subagent specs).\nThe implementation lives in the host (the same one behind the user's `/refine`\ncommand); this skill is the kernel-side interface to it. Call it directly from\nthe Python REPL:\n\n```python\nawait refine.status()\nawait refine.run()\nawait refine.run(\"create a memory about always checking git status before committing\")\nawait refine.run(\"promote the error-handling pattern to a global skill\", global_=True)\n```\n\n## API\n\n- `await refine.status()` — current refine state as a dict: `pending` (whether a\n  requested refine is already queued for this turn) and `in_flight` (whether a\n  refine is currently planning or applying).\n- `await refine.run(instructions=None, global_=False)` — schedule refinement.\n  Returns `{\"scheduled\": True}` immediately, or `{\"scheduled\": False, \"reason\": ...}`\n  when refinement cannot start. Optional `instructions` focus the refinement on a\n  specific observation. Set `global_=True` to target the global harness store\n  (cross-session); omit for local (session-scoped) refinement.\n\n## Rules\n\n- Refinement never runs mid-cell. A scheduled refinement runs when the current\n  turn ends; the harness applies changes and rebuilds the system prompt, then\n  resumes you automatically. Continue working normally after calling it.\n- One request per turn is enough; calling `run` again before the turn ends only\n  updates the instructions.\n- Use refinement after observing a repeated failure, a reusable tactic, a\n  repeated delegation role, or a behavior policy worth persisting. Do not\n  rewrite the whole harness when a focused memory, skill, prompt note, or\n  subagent spec is enough.\n","skills/rlm-heartbeat/SKILL.md":"---\nname: rlm-heartbeat\ndescription: Manage agent-owned RLM heartbeats from the Python REPL. Use when the user asks the agent to start, create, schedule, or manage a heartbeat, unless they explicitly request the user's /heartbeat.\n---\n\n# RLM Heartbeat\n\nRLM heartbeats are internal recurring prompts for the current agent session.\nThey are separate from the user's visible `/heartbeat`: this skill cannot read,\nreplace, pause, resume, or clear that user-level heartbeat.\n\nCall directly from the Python REPL:\n\n```python\nawait rlm_heartbeat.create(\"check test progress\", interval=\"5m\", label=\"tests\")\nawait rlm_heartbeat.create(\"watch build\", delivery_mode=\"follow_up\")\nawait rlm_heartbeat.list()\nawait rlm_heartbeat.update(\"job-id\", status=\"pause\")\nawait rlm_heartbeat.delete(\"job-id\")\n```\n\n## API\n\n- `await rlm_heartbeat.list(include_inactive=False)` — list this session's\n  internal RLM heartbeats. By default this includes active and paused entries.\n- `await rlm_heartbeat.create(instruction, interval=None, label=None,\n  delivery_mode=None)` — create a recurring heartbeat for this session. The\n  default interval is every 5 minutes. Multiple RLM heartbeats may run at once;\n  use labels to distinguish them. `delivery_mode` is `\"steer\"` (default) or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.update(id, instruction=None, interval=None, label=None,\n  status=None, delivery_mode=None)` — update one RLM heartbeat by id. `status`\n  may be `\"pause\"` or `\"resume\"`; `delivery_mode` may be `\"steer\"` or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.delete(id)` — cancel one RLM heartbeat by id.\n\n## Delivery mode\n\nEach heartbeat has a delivery mode controlling how the scheduled prompt reaches\nthe session when it is busy:\n\n- `steer` (default): interrupt the current turn so the heartbeat runs promptly.\n- `follow_up`: wait for the current turn to finish before running the heartbeat.\n\n## Rules\n\n- Use this when the user asks you to start, create, schedule, or manage your own\n  heartbeat without explicitly referring to `/heartbeat`.\n- Use this only for agent-internal recurring checks and long-running task\n  coordination.\n- Do not use this skill to satisfy a user's request to configure `/heartbeat`;\n  that is a separate user-level surface.\n- Keep heartbeat instructions specific and actionable so each recurring turn\n  knows exactly what to inspect or continue.\n","skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Create, validate, and install Prime Agent skills - both markdown skills and Python-backed skills callable from the Python kernel. Use when the user asks to create a skill, turn a workflow, script, or prompt into a reusable skill, add a Python skill the agent can call, or asks how to write a SKILL.md and where skills live.\n---\n\n# Skill Creator\n\nA skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup Prime Agent reads only each skill's name and description into the system prompt; the full file loads on demand when a task matches. Prime Agent follows the [Agent Skills standard](https://agentskills.io/specification) and extends it with Python-backed skills.\n\n| Kind | What it is | When to use |\n|---|---|---|\n| markdown | `SKILL.md` plus optional scripts, references, and assets | Workflows, CLI recipes, domain knowledge, multi-step instructions |\n| python | A markdown skill that also ships a Python package installed into the agent's persistent Python kernel | Capabilities that are naturally one Python call: API wrappers, fetchers, converters, computations |\n\nBefore writing a Python-backed skill, read [references/python-skills.md](references/python-skills.md) for the package contract.\n\n## Creating a Skill\n\n1. **Pick the kind.** Default to markdown. Go Python only when the agent should *call* the capability (`await my_skill(...)`) instead of following instructions.\n2. **Pick the location.** Ask the user when it is not obvious from context:\n   - Project skill, shared via the repo: `.prime/agent/skills/<name>/`\n   - Personal global skill: `~/.prime/agent/skills/<name>/`\n   - Shipped with an npm package: a `skills/` directory in the package, or `pi.skills` paths in its `package.json`\n3. **Scaffold and write** the directory using the layout and frontmatter rules below.\n4. **Verify** the skill loads (see Verification).\n\nOn a name collision the first skill found wins. Precedence: explicit `--skill` paths and `skills` settings entries, then project, then global, then package, then built-in skills.\n\n## Layout\n\n```\nmy-skill/\n├── SKILL.md              # Required: frontmatter + instructions\n├── scripts/              # Optional helper scripts the instructions reference\n├── references/           # Optional detailed docs, loaded only when needed\n└── assets/               # Optional templates and data files\n```\n\nEverything except `SKILL.md` is freeform. Reference files with paths relative to the skill directory; the agent resolves them against the directory containing `SKILL.md`.\n\n## Frontmatter\n\n```markdown\n---\nname: my-skill\ndescription: What this skill does and when to use it. Be specific.\n---\n```\n\n| Field | Required | Rules |\n|---|---|---|\n| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. No leading/trailing/consecutive hyphens. Must match the parent directory name. |\n| `description` | Yes | Max 1024 chars. A skill with a missing or empty description is **silently not loaded**. |\n| `disable-model-invocation` | No | `true` hides the skill from the system prompt; only explicit `/skill:<name>` invokes it. |\n| `license` | No | License name or reference to a bundled file. |\n| `compatibility` | No | Max 500 chars. Environment requirements. |\n| `metadata` | No | Arbitrary key-value mapping. |\n| `allowed-tools` | No | Space-delimited pre-approved tools (experimental). |\n\nUnknown fields are ignored. Name violations produce warnings but the skill still loads.\n\n### Write the description for routing\n\nThe description is the only thing the model sees before deciding to load the skill. State what the skill does *and* the trigger conditions (\"Use when ...\"), naming the concrete tasks, tools, and phrases a request would contain.\n\nGood: `Extracts text and tables from PDF files, fills PDF forms, and merges PDFs. Use when working with PDF documents.`\nPoor: `Helps with PDFs.`\n\n### Write the body for progressive disclosure\n\nKeep `SKILL.md` short: the decision flow, the common commands, the contract. Push exhaustive detail (API schemas, full option lists, long examples) into `references/*.md` and link them, so they only enter context when actually needed. State setup steps (installs, env vars, credentials) explicitly and early.\n\n## Verification\n\nAfter writing the skill:\n\n1. Re-read the frontmatter and check every rule in the table above, especially that `name` matches the directory name and the description is non-empty.\n2. In an interactive session, `/reload` picks up new skills without a restart; other sessions pick them up on start. Loading problems (bad name, missing description, name collisions) surface as warnings — ask the user to check, or check diagnostics yourself if you can.\n3. A loaded skill is also invocable as `/skill:<name>`, which the user can try directly.\n\nFor Python-backed skills, also run the checks in [references/python-skills.md](references/python-skills.md).\n","skills/skill-creator/references/python-skills.md":"# Python-Backed Skills\n\nA Python-backed skill is a regular markdown skill that also ships a Python package. Prime Agent installs the package editable into the kernel venv (`~/.prime/agent/kernel-venv` by default, `PRIME_AGENT_KERNEL_VENV` to override) and exposes it in the persistent Python kernel, so the agent can call it directly instead of shelling out.\n\n## Detection Contract\n\nAll of these must hold or the skill silently degrades to a markdown-only skill (with a load warning):\n\n- `SKILL.md` exists as usual.\n- `pyproject.toml` exists at the skill root — its presence is what marks the skill as Python-backed.\n- The import name is the skill name with hyphens converted to underscores, and it must be a valid Python identifier.\n- `src/<import_name>/__init__.py` exists (src layout, exact directory name).\n\nFor a skill named `word-count`, the kernel exposes `word_count`.\n\n## Minimal Template\n\n```\nword-count/\n├── SKILL.md\n├── pyproject.toml\n└── src/\n    └── word_count/\n        └── __init__.py\n```\n\n**`SKILL.md`**\n\n```markdown\n---\nname: word-count\ndescription: Count word frequencies in text and return the most common words. Use when the user asks for word counts or frequency analysis of a text snippet.\n---\n\n# Word Count\n\nCall directly from the kernel:\n\n    await word_count(\"some text to analyze\", top=3)\n\nOr from a shell cell:\n\n    !word_count \"some text to analyze\" --top 3\n```\n\n**`pyproject.toml`**\n\n```toml\n[project]\nname = \"word-count\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = []\n\n[project.scripts]\nword_count = \"rlm.skill:cli\"\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/word_count\"]\n```\n\n**`src/word_count/__init__.py`**\n\n```python\nfrom collections import Counter\n\n\nasync def run(text: str, top: int = 5) -> str:\n    \"\"\"Count words in text and return the most common ones.\"\"\"\n    counts = Counter(text.lower().split())\n    return \"\\n\".join(f\"{word}: {count}\" for word, count in counts.most_common(top))\n```\n\nThe `[tool.hatch.build.targets.wheel]` section is required with hatchling whenever the project name differs from the package directory name (it always does for hyphenated skill names).\n\n## The run() Convention\n\nIf `src/<import_name>/__init__.py` defines `run()`, the kernel wraps the module so the module itself is an async callable:\n\n```python\nawait word_count(\"text\")        # same as word_count.run(\"text\")\nawait word_count.run(\"text\")\nhelp(word_count)                # shows run()'s docstring and signature\n```\n\n- `run()` may be sync or async; the wrapper awaits awaitable results.\n- The signature and docstring of `run()` are copied onto the module, so write a real docstring and typed keyword arguments with defaults — they are the skill's API documentation *and* its CLI.\n- Without `run()`, the module is still imported and exposed by name, just not callable.\n- Import failures do not break the kernel: the name is bound to a placeholder that raises a `RuntimeError` containing the import error when called.\n\n## Optional CLI Command\n\nThe `[project.scripts]` entry pointing at `rlm.skill:cli` gives the skill a shell command. Rules:\n\n- The script name must **exactly** match the Python import name, underscores included (`word_count`, not `word-count`).\n- `rlm.skill:cli` imports `<script_name>.run` and parses argv against its signature with `tyro`, awaits async results, and prints non-`None` return values.\n- `rlm` and `tyro` are already present in the kernel venv. Do **not** declare `prime-agent-runtime` as a dependency: it is bundled with Prime Agent, not published on PyPI, so declaring it breaks installs outside the kernel venv. The CLI entry point only works where the runtime is installed, i.e. inside the kernel venv.\n\nThe agent can then use either form:\n\n```python\nawait word_count(\"prime agent\", top=3)\n```\n\n```bash\n!word_count \"prime agent\" --top 3\n```\n\nOmit `[project.scripts]` when a CLI is not needed.\n\n## Dependencies and the Kernel Venv\n\n- Declare every third-party package `run()` imports in `dependencies` — `pyproject.toml` is the source of truth. The one exception is `prime-agent-runtime` (see above).\n- These are already in the kernel venv, so depending on them is free: `requests`, `httpx`, `pyyaml`, `tomli`, `python-dotenv`, `pandas`, `numpy`, `scipy`, `beautifulsoup4`, `lxml`, `pydantic`, `tyro`.\n- The install is editable and keyed on a hash of `pyproject.toml`: editing Python source takes effect on the next kernel start with no reinstall; editing `pyproject.toml` triggers a reinstall automatically.\n- If the user sets `PRIME_AGENT_KERNEL_PYTHON`, Prime Agent installs nothing — skills whose imports are missing there are disabled with a warning.\n\nA Python skill runs inside the agent's kernel, so it can itself spawn recursive sub-agents with `import rlm` and `await rlm.spawn(\"subtask\", name=\"worker\")` — useful for skills that delegate open-ended work.\n\n## Verifying a Python Skill\n\n1. Check the contract: skill name maps to a valid identifier, `src/<import_name>/__init__.py` exists, hatchling wheel packages list matches.\n2. Test `run()` standalone from the skill directory, without the kernel:\n\n   ```bash\n   cd <skill-dir> && uv run python -c \"import asyncio, word_count; print(asyncio.run(word_count.run('a b a', top=1)))\"\n   ```\n\n3. In a fresh agent session (the kernel installs skills at startup), confirm `help(<import_name>)` shows the docstring and `await <import_name>(...)` works. If it raises `RuntimeError`, the message contains the underlying import error.\n","skills/websearch/SKILL.md":"---\nname: websearch\ndescription: Search Google via the Serper API. Configure access via /mcp, then Serper (web search). Takes one query and returns titles, URLs, snippets, and knowledge-graph data.\n---\n\n# Web Search\n\nSearch the web via the Serper Google Search API.\n\n## Setup\n\nGet a free API key at https://serper.dev, then run `/mcp` in Prime Agent and\nchoose **Serper (web search)** to paste it.\nThe key is stored in Prime Agent and made available to this skill automatically.\n\nIf web search reports a missing key, walk the user through those two steps;\ndon't ask them to set environment variables.\n\nOptional overrides (environment variables):\n\n- `PRIME_AGENT_WEBSEARCH_TIMEOUT` - HTTP timeout in seconds (default 45).\n- `PRIME_AGENT_WEBSEARCH_NUM_RESULTS` - number of organic results to return (default 5).\n\n## Usage\n\nCall the prepared `websearch` import directly in the Python kernel:\n\n```python\nprint(await websearch(\"latest Prime Agent release\"))\n```\n"},"files":{"AGENTS.md":"# AGENTS.md\n\nDevelopment rules for Prime Agent (Rust) on PrimeIntellect-ai/prime-agent, branch `main`.\nEvery contributor (human or agent) must read this before working on this repo.\n\n## Repository\n\n- **Never set git identity for commits to this repo's history.** Agents must not set\n  `user.name`/`user.email` (config or `-c`) or `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/\n  `GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` for commits that land in this repository.\n  Those commits carry the identity of the ambient git config. If such a commit fails for a\n  missing identity, report it instead of adding config. Allowed: the `*_DATE` variables\n  (the golden corpus pins them for reproducibility), throwaway temp repos created by\n  tests, and the release automation's bot identity.\n- **Never add `Co-authored-by` trailers** — not in commit messages, not in squash\n  suggestions, not as attribution for work merged from branches. A PR's commits carry\n  one identity: the ambient git config's. Fabricated or hand-written trailers (including\n  noreply forms) misattribute commits to unrelated GitHub accounts.\n- The repo is PrimeIntellect-ai/prime-agent; the Rust implementation lives on the `main` branch.\n- PRs go to the org repo with base `main`:\n  `gh pr create --repo PrimeIntellect-ai/prime-agent --base main`.\n- CI runs on the org's billing: `.github/workflows/continuous.yml` on `main` pushes and\n  `release.yml` on version tags.\n- Parity ground truth is unchanged: a read-only checkout of the TS implementation (this\n  repo at tag `v0.9.8`, the last TS release before the Rust port merged to `main`). Clone\n  it to `~/prime-agent`, the conventional location the parity scripts and code fall back\n  to; tooling that honors an override reads `PA_TS_REFERENCE`.\n\n## Style and structure\n\n- Workspace crates are prefixed `pa-`. The hard ownership rules: one owned area per crate,\n  pa-types is the only shared crate, cycle-free dependency direction, minimal public APIs,\n  no god-modules. The dependency direction is pinned in the Crates table below; each crate's\n  README.md states its scope, non-goals, and public API surface.\n- Prefer private modules with an explicitly exported public crate API. Internals are `pub(crate)`.\n- Aim for files under 2,000 lines, tests included. The 2,000-2,100 range is a soft review\n  signal, not a merge limit: when adding to an already-large file, consider splitting by\n  responsibility rather than growing it further. Move related tests and docs with extracted code.\n- Name modules for what they own, not `utils` or `common`. Follow existing structure: in\n  `crates/pa-core/src/kernel/manager/`, `mod.rs` connects `execution.rs`, `requests.rs`, and\n  `teardown.rs`; put a new kernel-manager concern beside them. In\n  `crates/pa-core/src/cron/store/`, `mod.rs` connects `heartbeat.rs`, `jobs.rs`, and\n  `session_artifacts.rs`; keep storage work there rather than growing the scheduler.\n- Inline format args: always prefer `format!(\"{x}\")` over positional.\n- Collapse if statements per clippy::collapsible_if.\n- Prefer method references over closures per clippy::redundant_closure_for_method_calls.\n- Make `match` statements exhaustive; avoid wildcard arms.\n- New traits need doc comments explaining their role and how implementations are expected to behave.\n- No opaque positional `bool`/`Option` parameters (`foo(false)` is unreadable). Prefer enums,\n  named methods, or newtypes. If you must pass an opaque literal by position, use an exact\n  `/*param_name*/` comment matching the callee signature.\n- Prefer native RPITIT trait methods with explicit `Send` bounds\n  (`fn foo(&self) -> impl Future<Output = T> + Send;`) over `#[async_trait]` or\n  `#[allow(async_fn_in_trait)]`. Implementations may use `async fn` when they satisfy the contract.\n- No single-use helper methods. Do not create a helper referenced only once.\n- Instrument async work at the definition (`#[tracing::instrument(...)]`), not with\n  `.instrument(...)` at call sites. Check whether the callee is already instrumented first.\n\n## Change hygiene\n\n- One logical change per PR. Fixes ride with the change that introduced them when possible; a PR\n  that mixes a feature with unrelated lint fixes or refactors hides both from review.\n- If you change dependencies (`Cargo.toml`), regenerate/commit `Cargo.lock` in the same change.\n  A new dependency is an architectural change: state in the PR why the existing crates cannot\n  host the functionality, and `make deny` must stay clean for it.\n- If a change starts forcing edits across many crate internals, stop and fix the boundary instead.\n\n## Tests\n\n- Prefer whole-object equality comparisons over field-by-field checks.\n- Do not add tests for statically defined values.\n- Do not add negative tests for logic that was removed.\n- Bug fixes need a regression test that fails without the fix.\n- Verifiers over self-assessment: tmux user-level tests, differential tests against the TS binary\n  on PATH, golden corpora replayed against real captured data. No lane merges without its verifier\n  passing, rerun by the reviewer where feasible.\n- Tests must wait for observable readiness, not fixed sleeps or retry-to-green loops. If a\n  test must be disabled, give a reason at the test. Use isolated ports and temporary paths, and\n  restore shared state. Run focused tests when changing their behavior.\n\n## Lint discipline\n\n- Zero-warning posture: the merge gates run fmt + clippy + tests at `-D warnings`, so a `warn`\n  lint is a merge blocker. Keep the enabled set deliberate and selective; enable a new lint family\n  only with every current site fixed in the same change.\n- Explain lint exceptions next to the `#[allow(...)]` or workspace configuration; keep\n  exceptions narrow. Advisory ignores in `deny.toml` need a reason and review date.\n\n## Performance and the critical path\n\nThe UI critical path is paint-latency-critical. First paint, and every\nframe the user waits on, must never block on network, disk sync, or\nbackground bookkeeping. The launch benchmarks measure this surface\n(cold/warm ready, first paint); a merge that regresses them undoes the\nproduct's core claim.\n\nRules:\n\n- Nothing user-visible awaits the network. Any HTTP/socket call on a\n  render path (telemetry, catalog fetch, update check) runs on a\n  background worker; the paint path hands the work off and returns\n  immediately. Delivery semantics (timeout, retry, ordering) live with\n  the worker, not the caller.\n- Telemetry is fire-and-forget from user-facing code. `pa-telemetry`'s\n  background worker owns delivery end to end; no startup, session\n  create, tab open, or first-render path may hold a flush or await a\n  sink.\n- Fire-and-forget boundaries need a red-first test: a hanging sink\n  (one that never replies) must not delay paint. The test fails if any\n  await on the critical path reaches the worker's delivery.\n- Tests that mock a sink or run offline cannot prove the above (the\n  benchmark's mock hides the POST). The regression test with a hanging\n  sink is the required verifier.\n\nExample (the #3288 regression this rule exists to prevent): the\ntelemetry startup flush was awaited on the interactive launch path, so\nthe analytics POST — a real HTTPS round-trip, ~157 ms — ran before the\nfirst frame. Every CI check passed because tests set DO_NOT_TRACK=1 and\nthe benchmark mocked the provider offline; only real-network launches\npaid the cost. The fix moved the flush to the background worker and\nadded `the_startup_flush_never_blocks_the_first_frame` (a hanging sink\nmust not delay paint) as the permanent guard. Any change touching the\nlaunch path must keep that test red-first.\n\n\n## Merge gates\n\n- `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`,\n  `cargo test --workspace` must pass before every merge. Run `make check` — the local mirror of\n  the same gates; CI runs on the org's billing (`.github/workflows/continuous.yml` on `main`\n  pushes; `release.yml` on version tags). The PR-only codebase-health check reports growth\n  past 2,000 lines as review guidance; it never blocks a merge.\n- **Parity-diff evidence is a merge gate** (the port's definition, not optional polish): every PR\n  that touches a user-visible surface must include a \"parity-diff evidence\" section in its\n  description showing the TS-binary comparison for what it changed: (1) rendered output —\n  frame-diff vs the TS binary;\n  (2) interactive behavior — the same input handled identically (keys, mouse, timing); \n  (3) wire parity — byte-compare the TS daemon's traffic for protocol changes; (4) user-visible\n  invariants — every user action produces the same visible reaction as TS (`/compact` shows\n  started+completed; `/model` shows the selector; a refinement shows its decoration). A feature\n  that \"works\" but was never diffed against the TS binary does not pass review. If TS shows it,\n  Rust shows it identically; if Rust shows something TS does not, that is also a parity bug.\n- PRs must state ownership compliance (crate README scope/non-goals/public API, dependency\n  direction) and classify the change: internals, new `pub` surface, or a new\n  dependency/cross-crate re-export. The latter two are architectural changes — an innocent-looking\n  `pub use` is a very simple way to break encapsulation.\n- The compiled fallback model catalog `crates/pa-ai/src/models_generated.rs` is\n  hand-maintained Rust mirroring the TS `packages/ai/src/models.generated.ts` object\n  literal — edit it by hand, exactly like its TS source (there is no generator). The\n  parity fixture `crates/pa-models/tests/fixtures/catalog.v1.json` refreshes with\n  `scripts/generate-catalog-fixture.py`. Bulk data files are exempt from the size guidance.\n\n## Adoption telemetry\n\nEvery user-visible feature ships its adoption telemetry event in the same PR as the feature:\nthe event name + properties join the versioned schema (`pa-telemetry`), and a\nseam emits it from day one. Telemetry properties never carry prompt, session, or file content\n(primitives only; see `pa-telemetry`); delivery is fire-and-forget from user-facing code\n(see Performance and the critical path).\n\n## Branding\n\nThe product is Prime Agent - we are not a pi fork. Scrub \"pi\"/\"pi-mono\"/\"pi-ai\"/\n\"Prime Intellect\"-style naming from all user-visible surfaces (docs, READMEs,\nCLI help text, error messages, splash/onboarding strings, keybinding hints, TUI\nlabels, and code comments that quote user-facing strings); brand everything\nPrime Agent. Audit with a repo-wide grep and classify every hit (user-visible\nvs wire-internal vs comment) before scrubbing, and list the preserved wire\nidentifiers in the PR body so the reviewer can verify none were wrongly scrubbed.\n\nEXPLICIT EXCEPTION: wire-protocol identifiers that must stay byte-compatible with the TS product (e.g. the PI_PACKAGE_DIR env var, settings keys, provider IDs like prime-inference, harness _meta namespaces like ai.primeintellect.prime-agent, lockfile names) stay until/unless the TS side renames them — PARITY BEATS BRANDING ON THE WIRE.\n\n\n\n## Surface contract (must not change)\n\n- Tools exposed to the model: `bash`, `edit`, `python_repl` (internal helpers: `rename`, `stdout`).\n- RLM kernel API in the persistent Python REPL: `rlm.spawn/find_models/collect/list_subagents/delete_subagent/create_session/progress_note`, `rlm.harness` CRUD, `agent_message.send`, `agent_observe`, `compact`, `goal`, `refine`, `attach_image`, skills (markdown + Python) per the skill contract in the base system prompt.\n- System prompt structure: layered — cache-stable static layer files (core harness description with the full API surface, mandatory usage rules, opinionated guidelines, per-model additions from the model-prompts TOML rule map) followed by one dynamic tail (packages, project context, skills inventory, MCP servers, environment, session role); the harness digest stays a separate `[harness-digest]` user message. `prime-agent prompt` dumps the assembled prompt with its layer breakdown.\n- CLI shape: `prime-agent` with the same commands/flags as the TS product; headless modes (RPC/daemon/session-worker) with identical behavior.\n\n## Crates\n\nOne owned area per crate; `pa-types` is the only shared vocabulary crate.\nDependencies flow from the composition root toward lower crates, never back upward.\nThe table summarizes each crate's current direct workspace dependencies:\n\n| Crate | Purpose | Direct workspace dependencies |\n| --- | --- | --- |\n| `pa-types` | Shared wire and domain types | none |\n| `pa-telemetry` | Events and sinks | none |\n| `pa-agent` | Provider-independent agent loop | none |\n| `pa-ai` | Providers, model registry, streaming | `pa-types` |\n| `pa-models` | Live model catalog and transport | `pa-ai`, `pa-types` |\n| `pa-core` | Session engine, tools, skills, kernel, settings | `pa-types`, `pa-ai`, `pa-models`, `pa-agent`, `pa-telemetry` |\n| `pa-daemon` | Supervisor, workers, wire protocol | `pa-types`, `pa-core`, `pa-agent`, `pa-ai`, `pa-telemetry`, `pa-models` |\n| `pa-tui` | Terminal UI, daemon-wire client | `pa-types` |\n| `pa-cli` | `prime-agent` binary, composition root | `pa-types`, `pa-core`, `pa-ai`, `pa-agent`, `pa-daemon`, `pa-tui`, `pa-telemetry` |\n| `pa-perf` | Performance corpora + pty bench harness (dev/CI tooling, never shipped) | `pa-types`, `pa-core`, `pa-daemon` |\n\nLayering rules:\n\n- Dependencies only point from higher crates to lower crates shown above. No cycles or\n  reverse edges. The leaf crates are peers; add only the dependencies needed for their work.\n  Shared wire/domain vocabulary belongs in `pa-types`, not in a higher crate or a duplicate.\n- `pa-tui` renders from wire types and events; it does not link the session engine.\n- `pa-cli` is a composition root: it wires crates together and contains no business logic.\n\n## Reliability model\n\n- The daemon is a supervisor: it spawns one worker process per active session instead of hosting sessions in-process. Workers are supervised, restarted with backoff, and sessions persist on disk (append-only JSONL, same layout as `~/.prime/agent/sessions`) so reattach works even if the supervisor restarts.\n- No stubs, no `todo!()`, no swallowed errors (`anyhow` bubbling to UI is fine).\n\n## References\n\n- Cursor Bugbot's PR review rules (`.cursor/BUGBOT.md`) mirror the standards in this file - update both whenever either changes.\n","skills/agent-message/SKILL.md":"---\nname: agent-message\ndescription: Message an agent's parent, siblings, or direct children through the daemon. Discover reachable agents with agent_observe.list_agents, then send direct text without spoofing sender identity.\n---\n\n# Agent Message\n\nSend direct messages within the current agent's nuclear family through the\nlocal daemon: parent, siblings, and direct children only. Roots are siblings.\nThe daemon derives your sender identity from the current session; do not try\nto include a `from` field.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    receipt = await agent_message.send(\n        \"Please inspect the latest result.\",\n        receiver_role=\"child\",\n        receiver_name=child.session_name,\n    )\n    # Keep the child until this follow-up finishes so its result remains observable.\n```\n\n## API\n\n- `await agent_observe.list_agents()` (agent-observe skill) is the roster: it\n  lists the parent, siblings, and children this skill can reach, active or not,\n  with the `relationship` and `sessionName` that `send` takes as\n  `receiver_role` and `receiver_name`.\n- `await agent_message.send(message, receiver_role=\"parent\" | \"sibling\" | \"child\", receiver_name=None)` — sends one direct\n  text message to one family member. Sending to an inactive or idle completed\n  subagent wakes it and starts an ordinary follow-up turn in that same session\n  and context.\n  The child remains available only until its parent session closes. The daemon\n  resolves `receiver_role` within the current agent family; `receiver_name` is\n  required for siblings and children and omitted for the unique parent.\n  `send(\"all\", message)` broadcasts only to the family roster and returns\n  `{receipts: [...]}` in roster order; successful entries are ordinary receipts\n  and failed entries contain the target id and a short `error`. One failed delivery\n  does not reject successful deliveries. Messages always use steering delivery so\n  a busy target sees them during its active run. Returns a receipt with a\n  `deliveryStatus` field: `\"delivered\"` means the message reached an idle target's\n  context; `\"queued\"` means a steering message was accepted and will deliver when\n  the target's current work allows (`send` does not block waiting for that).\n  Delivered receipts carry `deliveredAt`, queued receipts carry `queuedAt`.\n\n## Safety\n\n- Do not delete a child immediately after `send`: delivered follow-ups may still\n  be running and queued receipts have not run yet. Wait until observation shows\n  the child is idle and its context is no longer needed before calling\n  `await rlm.delete_subagent(child)`.\n- Reach is limited to parent, siblings, and direct children; relay through an\n  intermediate child instead of messaging grandchildren or cousins directly.\n- Sender identity is daemon-derived and cannot be spoofed from Python.\n- The daemon enforces message size, rate, and pending-queue limits before\n  accepting delivery.\n","skills/agent-observe/SKILL.md":"---\nname: agent-observe\ndescription: Read-only roster and observation of an agent's parent, siblings, and direct children. Use to discover reachable agents and to inspect family status and bounded recent-message previews without mutating sessions.\n---\n\n# Agent Observe\n\nObserve the current agent's nuclear family through the local daemon: parent,\nsiblings, direct children, and self. `list_agents` is the one family roster and\ncovers every member `agent_message.send` can reach. `get_agent` also returns an\ninactive child's roster row. `recent_messages` reads live sessions only; it\ndoes not rehydrate an inactive member. They cannot read a root sibling that has\nno live session in this worker.\nThis skill is read-only: it can list family sessions, inspect one session, and fetch\nbounded recent message previews. It cannot prompt, steer, clear, kill, rename, or\notherwise mutate another session.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    worker = await agent_observe.get_agent(child.session_name)\n    recent = await agent_observe.recent_messages(child.session_name, limit=6)\n    # Deletion is a parent-owned RLM operation, not an observe mutation:\n    await rlm.delete_subagent(child)\n```\n\n## API\n\n- `await agent_observe.list_agents()` returns `current` (the calling agent's\n  own row) and `agents` (the family: parent, siblings, and direct children,\n  active or not; the caller is excluded from `agents`). Each row carries\n  `sessionId`, optional `sessionName`, `relationship`\n  (`parent`/`sibling`/`child`), `status` (`running`/`idle` for live sessions,\n  `inactive` without one), the live `activity` (`tool`/`model`/`compacting`/\n  `busy`/`user`/`idle`), `isSessionActive`, the counts known\n  for it (`messageCount`, `queuedCount`, `attachedClients`), `cwd` when the\n  roster row carries it, the parent edges (`parentActiveSessionId`,\n  `parentSessionId`) and `rlmChildId` for subagents, and `firstMessage`\n  (capped at 240 chars) for an inactive child. A member with no live session\n  has no `activeSessionId` and no live detail; address it with\n  `agent_message.send` using its `relationship` plus its `sessionName`, or its\n  `sessionId` when the member has no name. For direct children,\n  `await rlm.list_subagents()` also exposes parent-owned lifecycle handles.\n- `await agent_observe.get_agent(target)` returns `agent`, where `agent`\n  contains one agent summary (the same shape as the roster rows, including a\n  passive child's row). `target` is resolved like other live-session\n  selectors: active id, session id or name, or an unambiguous id suffix.\n- `await agent_observe.recent_messages(target, limit=8, max_chars=800)`\n  returns `agent` (the target's summary), `messages` (up to `limit` recent\n  bounded previews), the clamped `limit` and `maxChars`, and `truncated`\n  (true when older messages exist beyond the returned window). `limit` must be\n  1-50, and `max_chars` must be 80-2000. The target must be a live family\n  member: a member with no live session errors instead of hydrating.\n\n## Safety\n\n- This skill is read-only and exposes no mutation commands.\n- Targets outside the nuclear family are rejected; transcript reads follow the\n  same family rule as messaging.\n- Message access is bounded by count and per-message character limit.\n- Prefer status and recent previews for orchestration. Ask the user before\n  using observed context to steer or message another session.\n","skills/attach-image/SKILL.md":"---\nname: attach-image\ndescription: Load an on-disk image (PNG, JPEG, GIF, WebP) into the model's context as a viewable attachment so the model can directly SEE it — for screenshots, diagrams, charts, photos, or scanned pages. Use this when you need to perceive an image's visual contents. Requires a vision-capable model; errors clearly otherwise.\n---\n\n# Attach Image\n\nLoad on-disk images into the model's context as multimodal attachments. The\nimage is sent to the model the same way a pasted image is, so the model can\nactually look at it.\n\n## When to use this\n\n- The user points at an image file and wants you to look at it.\n- You need to read text, a chart, a diagram, or a layout from an image.\n- A screenshot needs visual interpretation.\n\n## When NOT to use this\n\nFor *programmatic* work on an image — measuring pixels, cropping, resizing,\ncomputing a hash, comparing files byte-by-byte — open it in the kernel with a\nlibrary instead:\n\n```python\nfrom PIL import Image\nimg = Image.open(\"diagram.png\")\nprint(img.size)\n```\n\nThat path does not put the image in the model's context; it only lets you\ncompute over it. Use `attach_image` when you need to *see* the image.\n\n## Usage\n\nCall the prepared `attach_image` import directly in the Python kernel:\n\n```python\nprint(await attach_image(\"diagram.png\"))\nprint(await attach_image(\"a.png\", \"b.jpg\"))\n```\n\nThe skill automatically resizes and compresses large images before loading them\ninto context. Animated images that need compression are flattened to their first\nframe. Transparent images that need compression are composited onto a neutral\ngray background. Extremely large images are rejected by pixel count before full\nprocessing. The original file is left untouched.\n\nSupported formats: PNG, JPEG, GIF, WebP. The skill errors if a file is not a\nsupported image, or if the current model is not vision-capable.\n","skills/compact/SKILL.md":"---\nname: compact\ndescription: Check context usage and compact the conversation from the Python REPL. Use when context is filling up and substantial work remains, so the session is summarized and you keep working instead of stopping early.\n---\n\n# Compact\n\nCompaction replaces older conversation history with a dense summary, freeing\ncontext so long-running work can continue. The implementation lives in the\nhost (the same one behind the user's `/compact` command); this skill is the\nkernel-side interface to it. Call it directly from the Python REPL:\n\n```python\nawait compact.status()\nawait compact.run()\nawait compact.run(\"keep the failing test names and the migration checklist\")\n```\n\n## API\n\n- `await compact.status()` — current context usage as a dict: `tokens`,\n  `context_window`, and `percent` (`None` right after a compaction until the\n  next model response), plus `scheduled` (whether a requested compaction is\n  already pending).\n- `await compact.run(instructions=None)` — schedule compaction. Returns\n  `{\"scheduled\": True}`, or `{\"scheduled\": False, \"reason\": ...}` when there\n  is nothing to compact yet. Optional `instructions` focus the summary on\n  what matters for the remaining work.\n\n## Rules\n\n- Compaction never runs mid-cell. A scheduled compaction runs when the\n  current turn ends; the harness then resumes you automatically with the\n  summary plus recent messages, and you continue the task.\n- The Python kernel persists through compaction — variables, imports, and\n  helpers you defined all remain available.\n- Compact at a natural boundary when context usage is high and substantial\n  work remains, instead of becoming terse or returning to the user early.\n  Check `await compact.status()` when unsure.\n- One request per turn is enough; calling `run` again before the turn ends\n  only updates the instructions.\n","skills/edit/SKILL.md":"---\nname: edit\ndescription: Replace an exact, unique string in an existing file. Use for targeted single-occurrence edits to files from the Python kernel instead of rewriting the whole file.\n---\n\n# Edit\n\nMake a targeted edit to an existing file by replacing one exact, unique\noccurrence of a string. `old_str` must appear exactly once in the file.\n\nCall directly from the kernel:\n\n    await edit(path=\"pkg/file.py\", old_str=old, new_str=new)\n\nUse exact old/new strings. If the text contains triple double quotes, use\ntriple single-quoted variables (`old = '''...'''`) or build `old`/`new` from\ninspected file slices. Returns a short confirmation; raises if `old_str` is\nmissing or matches more than once (widen the snippet to make it unique).\n\nOr from a shell cell:\n\n    !edit --path pkg/file.py --old-str \"...\" --new-str \"...\"\n","skills/factory/SKILL.md":"---\nname: factory\ndescription: Run state-machine workflows of spawned child agents: store a validated machine or dag spec as a continual-harness factory entry (rlm.harness.create_factory), then run, watch, stop, and resume it through rlm.factory. For the full authoring reference and API guide, call rlm.factory.help() in the kernel.\n---\n\n# Factory\n\nThe factory runs state-machine workflows of spawned child agents. A stored\nfactory entry — harness kind `factory`, written with\n`rlm.harness.create_factory` — declares the machine: states, each backed by\na subagent spec, plus guarded transitions between them. The spec validates\nat write time (machine form, or `dag` sugar that compiles to one; pass\nexactly one), and an invalid spec is never stored.\n`await rlm.factory.run('<spec_id>')` then spawns each state's subagent as an\nordinary child, feeds captured outputs into the successors' prompts, and\ndrives the run to quiescence in a background kernel task — the call\nreturns immediately and the run continues after the model turn ends. Use\nit when a workflow needs shape: fan-out, bounded loops (review/fix until a\nverdict approves), joins, or one child per list item.\n\n**For the full authoring reference and API guide — states, ports, guards,\njoins, foreach, residents, budgets and policies, and the `rlm.factory`\nrun/status/stop/resume/graph/watch calls with worked examples — call\n`rlm.factory.help()` in the kernel.** The guide lands with the factory-core\nPR; on builds without it, the module docstring in\n`prime-agent-runtime/src/rlm/factory.py` is the source of truth.\n\n## The opt-in gate\n\nThe factory ships disabled. `rlm.factory.help()` answers while it is off\n(the authoring guide stays readable before opting in), but every other\n`rlm.factory` call and every factory harness write refuses with one\nmessage: `the factory is disabled; run /factory on to enable it`. The\nuser turns it on with `/factory on` in the client (`/factory off`\ndisables it again — refused while the session still has live runs, and\non a lane-advertising client while the live-run count cannot be read, so\nan active factory never loses its stop path, `/factory status` reports\nit), which persists the\n`factory.enabled` setting in the agent dir's settings.json — the same\nsetting the daemon's `factory_activity` lane advertisement reads, so the\nTUI's factory dock group and page surface only on a client started while\nthe factory is enabled. If a call refuses with that message, tell the\nuser to run `/factory on` and restart the client.\n\n## Discovering machines\n\n- The machine library: machines are `MACHINE.md` files, one directory\n  per machine — the bundled seeds ship inside the runtime package (wheel\n  package data, `rlm/machines/<name>/MACHINE.md`; `PRIME_AGENT_MACHINES_DIR`\n  redirects that level at a team directory), and the personal library\n  lives under the agent dir. `prime-agent factory list | import | export`\n  manages them. The seeds are `builder`, `pr-manager`, and `review-sweep`.\n- The TUI factory page: the activity dock's `⚙ N factory` group (Enter or\n  click) opens one live diagram per run, newest run first. The up/down\n  arrows move the selection, Enter opens the selected run's action rows\n  (stop, or resume while it is paused — arrows to walk, Enter to run),\n  Esc closes.\n","skills/goal/SKILL.md":"---\nname: goal\ndescription: Manage the persistent thread goal from the Python REPL. Use to read goal status and budget usage, to start a goal when the user explicitly asks for one, or to mark the active goal complete once its objective is fully achieved.\n---\n\n# Goal\n\nThe thread goal is a persistent objective the harness keeps re-prompting you to\npursue across turns until it is complete. Goal state (status, token budget,\nusage accounting) lives in the host; this skill is the kernel-side interface to\nit. Call it directly from the Python REPL:\n\n```python\nawait goal.get()\nawait goal.create(\"ship the release notes\")\n# Only pass token_budget when the user explicitly asks for one:\n# await goal.create(\"ship the release notes\", token_budget=200000)\nawait goal.complete()\n```\n\n## API\n\n- `await goal.get()` — current goal as a dict: `goal` (or `None` when no goal\n  is set), `remaining_tokens`, and `completion_budget_report`. The `goal` dict\n  carries `objective`, `status`, `token_budget`, `tokens_used`,\n  `time_used_seconds`, and timestamps.\n- `await goal.create(objective, token_budget=None)` — start a new active goal.\n  Fails while a goal is still pending (active, paused, or budget-limited); a\n  completed or errored goal is replaced by the new one. Only create a goal when\n  the user or system/developer instructions explicitly ask for a persistent\n  long-running goal; do not infer goals from ordinary tasks. Set `token_budget`\n  only when an explicit token budget is requested.\n- `await goal.complete()` — mark the existing goal achieved. Use only when the\n  objective has actually been achieved and no required work remains; do not\n  call it merely because the budget is nearly exhausted or because you are\n  stopping work. When the result includes a `completion_budget_report`, report\n  that final usage to the user.\n\n## Rules\n\n- Goal status transitions other than completion (pause, resume, clear,\n  budget-limiting) are controlled by the user and the host; there is no API for\n  them here.\n- When an active goal is actually complete, call `await goal.complete()`; do\n  not merely say it is done — the harness keeps continuing the goal until the\n  completion call arrives.\n","skills/mcp/SKILL.md":"---\nname: mcp\ndescription: Use external MCP services generically from Python - search the supported-service catalog, inspect the user's connections, discover live tool schemas, and call tools on any connection (Notion, Linear, Slack, and the rest of the catalog) without per-service packages.\n---\n\n# MCP Services\n\nEvery external service reachable over MCP uses the same pre-imported `mcp`\nmodule. Adding a service is data (a catalog entry plus a user login), never a\nnew Python package, and there are no per-service skills to read.\n\n## Inventory: what can I use?\n\n```python\n# Supported catalog, one bounded page. More pages exist while nextCursor is not None.\npage = await mcp.list_plugins(connection_status=\"not_connected\", limit=50)\nresults = await mcp.search_plugins(\"notion\")          # bounded search\npage = await mcp.list_plugins()                       # default: first 50 entries\n\n# The user's actual connections. connectionId is the dispatch id everywhere below.\nconnections = await mcp.list_connections()\n```\n\nCatalog entries carry `connectionStatus` (`connected`, `pending`,\n`not_connected`, `setup_required`, `disabled`, `error`), `connectable`, and\nwhen connected the `connectionIds` you dispatch on. `connected` means a\nverified MCP handshake, not just stored credentials; `pending` means\ncredentials exist but verification hasn't run or succeeded yet. Entries may\nalso carry `setupHint` (why a service isn't connectable yet), `unverified`\n(imported but not vetted), `verifiedAt`/`toolCount`, and `connectionIds`\n(empty when not dispatchable). Entries with `setup_required` need a developer\napp or API key first — say so honestly instead of promising one-click.\n\n## Recommend, never connect\n\nIf a task would benefit from an unconnected service, name the real catalog\nentry (e.g. \"Connecting Notion would let me search your workspace directly\")\nand tell the user to open `/plugins` (or run `/mcp login <service>`) to connect.\nRecommendations and catalog lookups never install anything, open a browser,\nuse credentials, or request extra scopes. There is no agent-initiated connect\ncall in this slice; if the user connects mid-task, the connection activates on\nthe next call without a reload.\n\n## Discover, then call\n\n```python\n# Live tool metadata is cached per connection; schemas come from the server.\ntools = await mcp.search_tools(\"search workspace documents\", connection_id=\"notion\")\ntool = await mcp.describe_tool(\"notion\", \"notion-search\")   # {name, description, inputSchema}\ntools = await mcp.list_tools(\"notion\")                     # full tool list with schemas\n\nresult = await mcp.call_tool(\"notion\", \"notion-search\", {\"query\": \"roadmap\"})\n```\n\n- Discover before calling: don't assume tool names or arguments; read the\n  `inputSchema` with `describe_tool` and construct matching arguments.\n- `list_tools` returns the complete inventory or raises — never a silent\n  partial list. Returned schemas are isolated copies; mutate them freely.\n- `search_tools` without a `connection_id` searches at most 8 connections the\n  host reports as connected and reports its scope: `searched`, `unavailable`\n  (per-connection failures as fixed, redaction-safe summaries), and\n  `truncated` (narrow the query or pick a connection when it is set — the\n  result never claims to be exhaustive).\n- Prefer narrow catalog searches over paging the whole catalog; don't dump all\n  schemas into context.\n- Results are already-parsed Python (a `dict` for structured output, otherwise\n  a string). No `json.loads` needed.\n\n## Errors and permissions\n\n- `PermissionError` — the tool is excluded by the user's `enabledTools` /\n  `disabledTools` policy. Don't retry; tell the user.\n- `KeyError` — the tool or connection doesn't exist. Re-check with\n  `list_tools` / `list_connections`; tools can change across sessions.\n- `McpDiscoveryError` — the server's tool listing couldn't complete honestly\n  (broken pagination). No partial inventory is published; re-run, and ask the\n  user to reconnect if it persists.\n- `RuntimeError` — credentials are not available (`McpCredentialsUnavailable`:\n  ask the user to connect via `/plugins` or `/mcp login <service>`, never via\n  environment variables), a refresh failed, or the host bridge is unavailable.\n- `McpToolError` — the server flagged the call as an error. Surface the\n  message; don't blindly retry a write that may have already happened.\n\nCredentials never appear in inventory results, tool schemas, or errors.\n","skills/prime-intellect/SKILL.md":"---\nname: prime-intellect\ndescription: Work with Prime Intellect products via the prime CLI and Python SDKs - verifiers environments and the Environments Hub, evaluations (local and hosted), Hosted Training and prime-rl, code sandboxes, Prime Inference, GPU compute (pods and clusters), storage, and tunnels. Use when a task involves Prime Intellect, the prime CLI, verifiers, RL environments, evals, training, sandboxes, renting GPUs, Prime Inference models, or when the user asks what Prime Intellect is or what it offers.\n---\n\n# Prime Intellect\n\nPrime Intellect is an open superintelligence lab building open-source AGI infrastructure: a platform for RL environments, evaluations, post-training, inference, and globally distributed GPU compute. Prime Agent (this agent) is built by Prime Intellect, and the `prime` CLI is the default way to interface with every product below.\n\n## Product Map\n\n| Product | What it is | Details |\n|---|---|---|\n| verifiers | Python library for building LLM environments and evaluations | [environments.md](references/environments.md) |\n| Environments Hub | Platform library of community RL environments (`prime env`) | [environments.md](references/environments.md) |\n| Hosted Evaluations | Run evals on Prime-managed infra (`prime eval run --hosted`) | [environments.md](references/environments.md) |\n| Hosted Training | Post-train models against environments (`prime train`, Lab) | [environments.md](references/environments.md) |\n| prime-rl | Large-scale async RL framework for self-managed training | [environments.md](references/environments.md) |\n| Sandboxes | Secure disposable VM sandboxes for AI-generated code | [sandboxes.md](references/sandboxes.md) |\n| Tunnels | Public HTTPS URLs for local/sandboxed services | [sandboxes.md](references/sandboxes.md) |\n| Inference | OpenAI-compatible API for frontier models | [inference.md](references/inference.md) |\n| Compute | Rent single GPU pods or multi-node clusters | [compute.md](references/compute.md) |\n| Storage | Persistent disks shared between instances | [compute.md](references/compute.md) |\n\n## Prime CLI Setup\n\nDefault to the `prime` CLI for all Prime Intellect operations. If it is not installed:\n\n```bash\nuv tool install prime    # or: pip install prime\nprime login              # browser auth; or: prime config set-api-key\nprime config view        # verify configuration\n```\n\nThe same package provides the Python SDKs (e.g. `prime_sandboxes`, `prime_tunnel`). Source: https://github.com/PrimeIntellect-ai/prime\n\n## Live Documentation\n\nAuthoritative, current docs live at https://docs.primeintellect.ai. Any docs page is fetchable as Markdown by appending `.md` to its URL, and the full index is at https://docs.primeintellect.ai/llms.txt. When you need details not covered here (exact flags, API schemas, pricing, new features), fetch the live docs instead of guessing:\n\n```bash\ncurl -s https://docs.primeintellect.ai/llms.txt                      # discover pages\ncurl -s https://docs.primeintellect.ai/sandboxes/overview.md         # fetch a page as markdown\n```\n\nThe REST API is documented under `api-reference/` pages (OpenAPI spec: https://api.primeintellect.ai/openapi.json), with `https://api.primeintellect.ai` as the base URL.\n\n## Command Quick Reference\n\n```bash\n# Environments Hub\nprime env list --search \"math\"      # discover environments\nprime env info owner/name           # inspect one\nprime env install owner/name        # install locally\nprime env init my-env --v1          # scaffold a new environment\nprime env push                      # publish to the Hub\n\n# Evaluations\nprime eval run my-env -m openai/gpt-4.1-mini -n 5    # local smoke eval\nprime eval run owner/env --hosted --follow           # hosted eval with logs\n\n# Training\nprime lab setup                     # set up a Lab workspace (Hosted Training)\nprime train models                  # models, capacity, pricing\nprime train init && prime train rl.toml              # configure + launch a run\n\n# Sandboxes\nprime sandbox create python:3.11-slim --timeout-minutes 120\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox delete <sandbox-id>\n\n# Inference\nprime inference models              # list available models\n\n# Compute\nprime availability list             # GPU availability + pricing\nprime pods create                   # provision a pod\nprime pods ssh <pod-id>             # SSH in (needs: prime config set-ssh-key-path)\n```\n\n## Working Conventions\n\n- Prefer ecosystem-native paths (`prime env init`, `prime eval run`, `prime lab setup`) over custom scaffolding.\n- Smoke-test small (`-n 5`) before scaling evals or training; keep default result uploads unless the user explicitly opts out.\n- For non-trivial eval/training work, ask whether the user wants instruct models (`gpt-4.1` series, `qwen3` instruct) or reasoning models (`gpt-5` series, `qwen3` thinking, `glm` series).\n- Hosted Training launches from a CPU machine; self-managed `prime-rl` requires local GPU access and is a power-user path.\n- The dashboard at https://app.primeintellect.ai covers API keys, billing, teams, and anything the CLI does not.\n","skills/prime-intellect/references/compute.md":"# Compute & Storage\n\nPrime Intellect aggregates GPU capacity across providers: rent single GPU pods on demand or deploy multi-node clusters, with persistent network-attached storage.\n\nLive docs: `cli-reference/check-gpu-availability.md`, `cli-reference/provision-gpu.md`, `cli-reference/managing-disks.md`, `tutorials-multi-node-cluster/deploy-multi-node.md`, `tutorials-storage/create-persistent-storage.md` under https://docs.primeintellect.ai/\n\n## GPU Availability\n\n```bash\nprime availability list                        # all GPUs with pricing\nprime availability list --gpu-type H100_80GB   # filter by GPU type\n```\n\n## Pods (single instances)\n\n```bash\nprime config set-ssh-key-path   # one-time: SSH key for pod access (generate on the dashboard profile page)\nprime pods create               # interactive provisioning from availability data\nprime pods list\nprime pods ssh <pod-id>\n```\n\nPods support custom Docker images (`tutorials-on-demand-cloud/deploy-custom-docker-image.md`). Monitor, terminate, and inspect pods from the CLI or the dashboard.\n\n## Multi-Node Clusters\n\nDeploy multi-node clusters (with optional Slurm orchestration) from the platform; see `tutorials-multi-node-cluster/deploy-multi-node.md` and `tutorials-multi-node-cluster/slurm-orchestration.md`. Cluster monitoring guidance lives at `tutorials-reserved-clusters/monitoring.md`.\n\n## Storage\n\nPersistent disks outlive individual instances and can be attached to different instances as needed:\n\n- Create disks from the Storage tab of the Instances page (choose provider, datacenter, size), then attach them to pods or clusters.\n- Manage disks from the CLI as well — see `cli-reference/managing-disks.md`.\n- For multi-node shared and ephemeral storage patterns, see `tutorials-storage/cluster-storage.md`.\n\n## Teams\n\nManage team membership and run resources against team billing:\n\n```bash\nprime teams list\n```\n\nMost provisioning commands accept a `--team-id` flag; the REST API equivalent is the `X-Prime-Team-ID` header.\n","skills/prime-intellect/references/environments.md":"# Environments, Evaluations & Training\n\nverifiers is Prime Intellect's Python library for LLM environments: packages that expose `load_environment` and bundle datasets, rollout logic, and reward rubrics. Environments power evaluations (local and hosted) and RL training (Hosted Training or self-managed prime-rl).\n\nLive docs: `verifiers/overview.md`, `tutorials-environments/getting-started.md`, `hosted-training/getting-started.md`, `prime-rl/overview.md` under https://docs.primeintellect.ai/ (append `.md` for raw markdown). Source: https://github.com/PrimeIntellect-ai/verifiers and https://github.com/PrimeIntellect-ai/prime-rl\n\n## Discovering Environments (Hub)\n\n```bash\nprime env list --search \"math\" --owner primeintellect --show-actions\nprime env list --tag tools --tag sandbox\nprime env list --mine\nprime env list --starred\nprime env info owner/name        # metadata, version, dependencies\nprime env status owner/name      # CI/action status\nprime env pull owner/name -t ./tmp-env   # pull source for inspection\nprime env install owner/name     # install locally\n```\n\nWhen picking candidates, prefer: `primeintellect`-owned, passing latest actions, updated within ~2 months, recent verifiers versions. Compare task type (single-turn, multi-turn, tool, sandbox, agent), reward type (binary, continuous, judge-based), and dependency/secret requirements.\n\n## Creating Environments\n\n```bash\nprime env init my-env --v1       # scaffold (add --with-harness for an explicit reusable harness)\nprime env install my-env\nprime eval run my-env -m openai/gpt-4.1-mini -n 5   # smoke test immediately\nprime env push                   # publish to the Hub\n```\n\nBuild guidance:\n\n- Define the task contract first: prompt shape, allowed tools, stop conditions, rubric outputs, metrics.\n- Prefer starting from an existing Hub environment (`prime env list --search`, then `prime env install owner/name`) over building from scratch.\n- v1 environments expose `load_environment(config: vf.EnvConfig) -> vf.Env`; Taskset + Harness environments additionally expose `load_taskset(config)` and optionally `load_harness(config)` with `load_environment` delegating through `vf.load_taskset`/`vf.load_harness`.\n- The environment must install, load, evaluate, and train without hidden setup.\n\n## Evaluations\n\n`prime eval run` is the canonical eval path. Runs save automatically (visible in the Evaluations tab and `prime eval view`); do not add `--skip-upload` unless the user explicitly asks.\n\n```bash\nprime eval run my-env -m openai/gpt-4.1-mini -n 5               # smoke\nprime eval run owner/env -m openai/gpt-4.1-mini -n 200 -r 3 --shuffle -s   # scaled\nprime eval run owner/env --hosted --follow                       # hosted, streaming logs\n```\n\n- Smoke-test first; scale only after a pass. Use `--shuffle` (seed defaults to 0; set `--shuffle-seed` for reproducible reports).\n- Hosted evals require the environment to be published (`prime env push`) and support TOML configs and temporary sandbox/tunnel permissions (`--allow-tunnel-access`).\n- Prime Inference models include estimated run cost in eval output automatically.\n- Keep reusable model endpoints as aliases in `configs/endpoints.toml` (fields: `endpoint_id`, `model`, `url`, key) and reference them with `-m <endpoint_id>`.\n\n## Training\n\nDefault to Hosted Training unless the user explicitly wants self-managed infrastructure.\n\n```bash\nprime lab setup                  # Lab workspace for environments, evals, GEPA, Hosted Training\nprime train models               # supported models, capacity, pricing\nprime train init                 # generate a training config\nprime train rl.toml              # launch the run\n```\n\n- Hosted Training launches from a CPU machine; no local GPUs needed.\n- Validate the environment with an eval before training (e.g. `-n 20 -r 3 -s`) and confirm reward diversity exists at baseline.\n- Self-managed path: `prime lab setup --prime-rl`, then follow prime-rl's own configs and launch commands. Treat prime-rl as a power-user path requiring local GPU access; see https://docs.primeintellect.ai/prime-rl/overview.md.\n\n## Model Family Choice\n\nAsk the user whether they want instruct or reasoning models before non-trivial runs:\n\n- Instruct (quick behavior checks): `gpt-4.1` series, `qwen3` instruct series.\n- Reasoning (harder probes, deeper coverage): `gpt-5` series, `qwen3` thinking series, `glm` series.\n","skills/prime-intellect/references/inference.md":"# Prime Inference\n\nPrime Inference is an OpenAI-compatible API for frontier and open models, routed across providers and built for large-scale evaluations.\n\nLive docs: `inference/overview.md`, `inference/usage.md`, `inference/adapter-deployments.md`, `inference/troubleshooting.md` under https://docs.primeintellect.ai/\n\n## Setup\n\n1. Create an API key on https://app.primeintellect.ai (account settings → API Keys) with the **Inference** permission enabled — without it, requests fail with authentication errors.\n2. Export it:\n\n```bash\nexport PRIME_API_KEY=\"your-api-key-here\"\n```\n\n## Via the CLI (recommended for evaluations)\n\n```bash\nprime inference models                                   # list available models\nprime eval run gsm8k -m meta-llama/llama-3.1-70b-instruct -n 25   # evals route through Prime Inference\n```\n\nEval runs against Prime Inference models report estimated USD cost automatically.\n\n## Direct API (OpenAI-compatible)\n\nBase URL: `https://api.pinference.ai/api/v1`\n\n```python\nimport openai, os\n\nclient = openai.OpenAI(\n    api_key=os.environ[\"PRIME_API_KEY\"],\n    base_url=\"https://api.pinference.ai/api/v1\",\n)\nresponse = client.chat.completions.create(\n    model=\"meta-llama/llama-3.1-70b-instruct\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n```\n\nAnything that speaks the OpenAI API works — just point it at the base URL above. Streaming and advanced parameters are covered in `inference/usage.md`.\n\n## Teams & Adapters\n\n- Team billing: send the `X-Prime-Team-ID` header (find the ID via `prime teams list` or the Team Profile page) to use team credits instead of personal balance.\n- LoRA adapters trained with Hosted Training can be deployed and queried through the same OpenAI-compatible API (`inference/adapter-deployments.md`).\n","skills/prime-intellect/references/sandboxes.md":"# Sandboxes & Tunnels\n\nPrime Sandboxes are disposable VM environments for running AI-generated or untrusted code in the cloud: isolated, fast to create, billed only while running (CPU $0.05/core/hr, memory $0.01/GB/hr, disk $0.001/GB/hr).\n\nLive docs: `sandboxes/overview.md`, `sandboxes/cli.md`, `sandboxes/sdk.md`, `sandboxes/images.md`, `sandboxes/tunnel.md` under https://docs.primeintellect.ai/\n\n## CLI Lifecycle\n\n```bash\nprime sandbox create python:3.11-slim --timeout-minutes 120   # any Docker image\nprime sandbox list\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox get <sandbox-id>\nprime sandbox delete <sandbox-id>\n```\n\nUseful create flags:\n\n```bash\nprime sandbox create python:3.11-slim \\\n  --name analytics-lab \\\n  --cpu-cores 2 --memory-gb 4 --disk-size-gb 20 \\\n  --timeout-minutes 240 \\\n  --idle-timeout-minutes 15 \\\n  --env APP_ENV=staging \\\n  --secret API_KEY=sk-abc123 \\\n  --yes\n```\n\n- `--timeout-minutes` caps total lifetime; `--idle-timeout-minutes` reaps the sandbox early when no exec/upload/download/file-read arrives (1 ≤ idle ≤ timeout ≤ 1440; for VM sandboxes, `timeout_minutes` may be negative to disable the lifetime deadline).\n- `--env` values are plain text; `--secret` values are encrypted at rest and obfuscated in output. Both become environment variables inside the sandbox.\n- Default start command keeps the sandbox idle, ready for `prime sandbox run`. To run your own process at boot, pass the command after `--` as separate tokens (no shell): `prime sandbox create python:3.11-slim -- python serve.py --port 8000`.\n- Outbound internet is on by default; restrict egress with network allow/deny lists (`prime sandbox network`, or `network_allowlist`/`network_denylist` in the SDK).\n- `--team-id` bills a team; `--yes` skips confirmation in automation.\n\nCustom images: build and push your own via Prime Images (`sandboxes/images.md`).\n\n## Python SDK\n\n`prime_sandboxes` ships `SandboxClient` (sync) and `AsyncSandboxClient` (async) with identical methods:\n\n```python\nfrom prime_sandboxes import SandboxClient, CreateSandboxRequest, APIClient\n\nclient = SandboxClient(APIClient())\nsandbox = client.create(CreateSandboxRequest(\n    name=\"sdk-demo\",\n    docker_image=\"python:3.11-slim\",\n    timeout_minutes=120,\n    environment_vars={\"LOG_LEVEL\": \"debug\"},\n    secrets={\"API_KEY\": \"sk-abc123\"},\n))\nclient.wait_for_creation(sandbox.id)\nresult = client.execute_command(sandbox.id, \"python -c 'print(42)'\")\nclient.upload_file(sandbox.id, \"/workspace/data.csv\", \"./data.csv\")\nclient.download_file(sandbox.id, \"/workspace/output.csv\", \"./output.csv\")\nclient.delete(sandbox.id)\n```\n\nAsync variant: `async with AsyncSandboxClient() as sandboxes: await sandboxes.create(...)` — same methods, useful for fanning out many sandboxes concurrently.\n\n## Tunnels\n\nPrime Tunnel exposes a local (or in-sandbox) service through a secure public HTTPS URL — for dev servers, webhooks, and sharing work in progress:\n\n```python\nfrom prime_tunnel import Tunnel\n\ntunnel = Tunnel(local_port=8000)\nawait tunnel.start()   # prints the public URL\n```\n\nHosted evaluations can create tunnels too: launch the run with `--allow-tunnel-access` (grants tunnel permission to the temporary `PRIME_API_KEY`), then use the same flow inside the hosted sandbox.\n","skills/refine/SKILL.md":"---\nname: refine\ndescription: Trigger continual harness refinement from the Python REPL. Use when you notice a repeated failure, reusable tactic, delegation role, or behavior policy that should be persisted as a harness entry. Returns immediately; refinement runs when the current turn ends.\n---\n\n# Refine\n\nRefinement analyzes the conversation trajectory and applies small, evidence-backed\nupdates to the continual harness (prompts, memories, skills, subagent specs).\nThe implementation lives in the host (the same one behind the user's `/refine`\ncommand); this skill is the kernel-side interface to it. Call it directly from\nthe Python REPL:\n\n```python\nawait refine.status()\nawait refine.run()\nawait refine.run(\"create a memory about always checking git status before committing\")\nawait refine.run(\"promote the error-handling pattern to a global skill\", global_=True)\n```\n\n## API\n\n- `await refine.status()` — current refine state as a dict: `pending` (whether a\n  requested refine is already queued for this turn) and `in_flight` (whether a\n  refine is currently planning or applying).\n- `await refine.run(instructions=None, global_=False)` — schedule refinement.\n  Returns `{\"scheduled\": True}` immediately, or `{\"scheduled\": False, \"reason\": ...}`\n  when refinement cannot start. Optional `instructions` focus the refinement on a\n  specific observation. Set `global_=True` to target the global harness store\n  (cross-session); omit for local (session-scoped) refinement.\n\n## Rules\n\n- Refinement never runs mid-cell. A scheduled refinement runs when the current\n  turn ends; the harness applies changes and rebuilds the system prompt, then\n  resumes you automatically. Continue working normally after calling it.\n- One request per turn is enough; calling `run` again before the turn ends only\n  updates the instructions.\n- Use refinement after observing a repeated failure, a reusable tactic, a\n  repeated delegation role, or a behavior policy worth persisting. Do not\n  rewrite the whole harness when a focused memory, skill, prompt note, or\n  subagent spec is enough.\n","skills/rlm-heartbeat/SKILL.md":"---\nname: rlm-heartbeat\ndescription: Manage agent-owned RLM heartbeats from the Python REPL. Use when the user asks the agent to start, create, schedule, or manage a heartbeat, unless they explicitly request the user's /heartbeat.\n---\n\n# RLM Heartbeat\n\nRLM heartbeats are internal recurring prompts for the current agent session.\nThey are separate from the user's visible `/heartbeat`: this skill cannot read,\nreplace, pause, resume, or clear that user-level heartbeat.\n\nCall directly from the Python REPL:\n\n```python\nawait rlm_heartbeat.create(\"check test progress\", interval=\"5m\", label=\"tests\")\nawait rlm_heartbeat.create(\"watch build\", delivery_mode=\"follow_up\")\nawait rlm_heartbeat.list()\nawait rlm_heartbeat.update(\"job-id\", status=\"pause\")\nawait rlm_heartbeat.delete(\"job-id\")\n```\n\n## API\n\n- `await rlm_heartbeat.list(include_inactive=False)` — list this session's\n  internal RLM heartbeats. By default this includes active and paused entries.\n- `await rlm_heartbeat.create(instruction, interval=None, label=None,\n  delivery_mode=None)` — create a recurring heartbeat for this session. The\n  default interval is every 5 minutes. Multiple RLM heartbeats may run at once;\n  use labels to distinguish them. `delivery_mode` is `\"steer\"` (default) or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.update(id, instruction=None, interval=None, label=None,\n  status=None, delivery_mode=None)` — update one RLM heartbeat by id. `status`\n  may be `\"pause\"` or `\"resume\"`; `delivery_mode` may be `\"steer\"` or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.delete(id)` — cancel one RLM heartbeat by id.\n\n## Delivery mode\n\nEach heartbeat has a delivery mode controlling how the scheduled prompt reaches\nthe session when it is busy:\n\n- `steer` (default): interrupt the current turn so the heartbeat runs promptly.\n- `follow_up`: wait for the current turn to finish before running the heartbeat.\n\n## Rules\n\n- Use this when the user asks you to start, create, schedule, or manage your own\n  heartbeat without explicitly referring to `/heartbeat`.\n- Use this only for agent-internal recurring checks and long-running task\n  coordination.\n- Do not use this skill to satisfy a user's request to configure `/heartbeat`;\n  that is a separate user-level surface.\n- Keep heartbeat instructions specific and actionable so each recurring turn\n  knows exactly what to inspect or continue.\n","skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Create, validate, and install Prime Agent skills - both markdown skills and Python-backed skills callable from the Python kernel. Use when the user asks to create a skill, turn a workflow, script, or prompt into a reusable skill, add a Python skill the agent can call, or asks how to write a SKILL.md and where skills live.\n---\n\n# Skill Creator\n\nA skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup Prime Agent reads only each skill's name and description into the system prompt; the full file loads on demand when a task matches. Prime Agent follows the [Agent Skills standard](https://agentskills.io/specification) and extends it with Python-backed skills.\n\n| Kind | What it is | When to use |\n|---|---|---|\n| markdown | `SKILL.md` plus optional scripts, references, and assets | Workflows, CLI recipes, domain knowledge, multi-step instructions |\n| python | A markdown skill that also ships a Python package installed into the agent's persistent Python kernel | Capabilities that are naturally one Python call: API wrappers, fetchers, converters, computations |\n\nBefore writing a Python-backed skill, read [references/python-skills.md](references/python-skills.md) for the package contract.\n\n## Creating a Skill\n\n1. **Pick the kind.** Default to markdown. Go Python only when the agent should *call* the capability (`await my_skill(...)`) instead of following instructions.\n2. **Pick the location.** Ask the user when it is not obvious from context:\n   - Project skill, shared via the repo: `.prime/agent/skills/<name>/`\n   - Personal global skill: `~/.prime/agent/skills/<name>/`\n   - Shipped with an npm package: a `skills/` directory in the package, or `pi.skills` paths in its `package.json`\n3. **Scaffold and write** the directory using the layout and frontmatter rules below.\n4. **Verify** the skill loads (see Verification).\n\nOn a name collision the first skill found wins. Precedence: explicit `--skill` paths and `skills` settings entries, then project, then global, then package, then built-in skills.\n\n## Layout\n\n```\nmy-skill/\n├── SKILL.md              # Required: frontmatter + instructions\n├── scripts/              # Optional helper scripts the instructions reference\n├── references/           # Optional detailed docs, loaded only when needed\n└── assets/               # Optional templates and data files\n```\n\nEverything except `SKILL.md` is freeform. Reference files with paths relative to the skill directory; the agent resolves them against the directory containing `SKILL.md`.\n\n## Frontmatter\n\n```markdown\n---\nname: my-skill\ndescription: What this skill does and when to use it. Be specific.\n---\n```\n\n| Field | Required | Rules |\n|---|---|---|\n| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. No leading/trailing/consecutive hyphens. Must match the parent directory name. |\n| `description` | Yes | Max 1024 chars. A skill with a missing or empty description is **silently not loaded**. |\n| `disable-model-invocation` | No | `true` hides the skill from the system prompt; only explicit `/skill:<name>` invokes it. |\n| `license` | No | License name or reference to a bundled file. |\n| `compatibility` | No | Max 500 chars. Environment requirements. |\n| `metadata` | No | Arbitrary key-value mapping. |\n| `allowed-tools` | No | Space-delimited pre-approved tools (experimental). |\n\nUnknown fields are ignored. Name violations produce warnings but the skill still loads.\n\n### Write the description for routing\n\nThe description is the only thing the model sees before deciding to load the skill. State what the skill does *and* the trigger conditions (\"Use when ...\"), naming the concrete tasks, tools, and phrases a request would contain.\n\nGood: `Extracts text and tables from PDF files, fills PDF forms, and merges PDFs. Use when working with PDF documents.`\nPoor: `Helps with PDFs.`\n\n### Write the body for progressive disclosure\n\nKeep `SKILL.md` short: the decision flow, the common commands, the contract. Push exhaustive detail (API schemas, full option lists, long examples) into `references/*.md` and link them, so they only enter context when actually needed. State setup steps (installs, env vars, credentials) explicitly and early.\n\n## Verification\n\nAfter writing the skill:\n\n1. Re-read the frontmatter and check every rule in the table above, especially that `name` matches the directory name and the description is non-empty.\n2. In an interactive session, `/reload` picks up new skills without a restart; other sessions pick them up on start. Loading problems (bad name, missing description, name collisions) surface as warnings — ask the user to check, or check diagnostics yourself if you can.\n3. A loaded skill is also invocable as `/skill:<name>`, which the user can try directly.\n\nFor Python-backed skills, also run the checks in [references/python-skills.md](references/python-skills.md).\n","skills/skill-creator/references/python-skills.md":"# Python-Backed Skills\n\nA Python-backed skill is a regular markdown skill that also ships a Python package. Prime Agent installs the package editable into the kernel venv (`~/.prime/agent/kernel-venv` by default, `PRIME_AGENT_KERNEL_VENV` to override) and exposes it in the persistent Python kernel, so the agent can call it directly instead of shelling out.\n\n## Detection Contract\n\nAll of these must hold or the skill silently degrades to a markdown-only skill (with a load warning):\n\n- `SKILL.md` exists as usual.\n- `pyproject.toml` exists at the skill root — its presence is what marks the skill as Python-backed.\n- The import name is the skill name with hyphens converted to underscores, and it must be a valid Python identifier.\n- `src/<import_name>/__init__.py` exists (src layout, exact directory name).\n\nFor a skill named `word-count`, the kernel exposes `word_count`.\n\n## Minimal Template\n\n```\nword-count/\n├── SKILL.md\n├── pyproject.toml\n└── src/\n    └── word_count/\n        └── __init__.py\n```\n\n**`SKILL.md`**\n\n```markdown\n---\nname: word-count\ndescription: Count word frequencies in text and return the most common words. Use when the user asks for word counts or frequency analysis of a text snippet.\n---\n\n# Word Count\n\nCall directly from the kernel:\n\n    await word_count(\"some text to analyze\", top=3)\n\nOr from a shell cell:\n\n    !word_count \"some text to analyze\" --top 3\n```\n\n**`pyproject.toml`**\n\n```toml\n[project]\nname = \"word-count\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = []\n\n[project.scripts]\nword_count = \"rlm.skill:cli\"\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/word_count\"]\n```\n\n**`src/word_count/__init__.py`**\n\n```python\nfrom collections import Counter\n\n\nasync def run(text: str, top: int = 5) -> str:\n    \"\"\"Count words in text and return the most common ones.\"\"\"\n    counts = Counter(text.lower().split())\n    return \"\\n\".join(f\"{word}: {count}\" for word, count in counts.most_common(top))\n```\n\nThe `[tool.hatch.build.targets.wheel]` section is required with hatchling whenever the project name differs from the package directory name (it always does for hyphenated skill names).\n\n## The run() Convention\n\nIf `src/<import_name>/__init__.py` defines `run()`, the kernel wraps the module so the module itself is an async callable:\n\n```python\nawait word_count(\"text\")        # same as word_count.run(\"text\")\nawait word_count.run(\"text\")\nhelp(word_count)                # shows run()'s docstring and signature\n```\n\n- `run()` may be sync or async; the wrapper awaits awaitable results.\n- The signature and docstring of `run()` are copied onto the module, so write a real docstring and typed keyword arguments with defaults — they are the skill's API documentation *and* its CLI.\n- Without `run()`, the module is still imported and exposed by name, just not callable.\n- Import failures do not break the kernel: the name is bound to a placeholder that raises a `RuntimeError` containing the import error when called.\n\n## Optional CLI Command\n\nThe `[project.scripts]` entry pointing at `rlm.skill:cli` gives the skill a shell command. Rules:\n\n- The script name must **exactly** match the Python import name, underscores included (`word_count`, not `word-count`).\n- `rlm.skill:cli` imports `<script_name>.run` and parses argv against its signature with `tyro`, awaits async results, and prints non-`None` return values.\n- `rlm` and `tyro` are already present in the kernel venv. Do **not** declare `prime-agent-runtime` as a dependency: it is bundled with Prime Agent, not published on PyPI, so declaring it breaks installs outside the kernel venv. The CLI entry point only works where the runtime is installed, i.e. inside the kernel venv.\n\nThe agent can then use either form:\n\n```python\nawait word_count(\"prime agent\", top=3)\n```\n\n```bash\n!word_count \"prime agent\" --top 3\n```\n\nOmit `[project.scripts]` when a CLI is not needed.\n\n## Dependencies and the Kernel Venv\n\n- Declare every third-party package `run()` imports in `dependencies` — `pyproject.toml` is the source of truth. The one exception is `prime-agent-runtime` (see above).\n- These are already in the kernel venv, so depending on them is free: `requests`, `httpx`, `pyyaml`, `tomli`, `python-dotenv`, `pandas`, `numpy`, `scipy`, `beautifulsoup4`, `lxml`, `pydantic`, `tyro`.\n- The install is editable and keyed on a hash of `pyproject.toml`: editing Python source takes effect on the next kernel start with no reinstall; editing `pyproject.toml` triggers a reinstall automatically.\n- If the user sets `PRIME_AGENT_KERNEL_PYTHON`, Prime Agent installs nothing — skills whose imports are missing there are disabled with a warning.\n\nA Python skill runs inside the agent's kernel, so it can itself spawn recursive sub-agents with `import rlm` and `await rlm.spawn(\"subtask\", name=\"worker\")` — useful for skills that delegate open-ended work.\n\n## Verifying a Python Skill\n\n1. Check the contract: skill name maps to a valid identifier, `src/<import_name>/__init__.py` exists, hatchling wheel packages list matches.\n2. Test `run()` standalone from the skill directory, without the kernel:\n\n   ```bash\n   cd <skill-dir> && uv run python -c \"import asyncio, word_count; print(asyncio.run(word_count.run('a b a', top=1)))\"\n   ```\n\n3. In a fresh agent session (the kernel installs skills at startup), confirm `help(<import_name>)` shows the docstring and `await <import_name>(...)` works. If it raises `RuntimeError`, the message contains the underlying import error.\n","skills/websearch/SKILL.md":"---\nname: websearch\ndescription: Search Google via the Serper API. Configure access via /mcp, then Serper (web search). Takes one query and returns titles, URLs, snippets, and knowledge-graph data.\n---\n\n# Web Search\n\nSearch the web via the Serper Google Search API.\n\n## Setup\n\nGet a free API key at https://serper.dev, then run `/mcp` in Prime Agent and\nchoose **Serper (web search)** to paste it.\nThe key is stored in Prime Agent and made available to this skill automatically.\n\nIf web search reports a missing key, walk the user through those two steps;\ndon't ask them to set environment variables.\n\nOptional overrides (environment variables):\n\n- `PRIME_AGENT_WEBSEARCH_TIMEOUT` - HTTP timeout in seconds (default 45).\n- `PRIME_AGENT_WEBSEARCH_NUM_RESULTS` - number of organic results to return (default 5).\n\n## Usage\n\nCall the prepared `websearch` import directly in the Python kernel:\n\n```python\nprint(await websearch(\"latest Prime Agent release\"))\n```\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md\n\nDevelopment rules for Prime Agent (Rust) on PrimeIntellect-ai/prime-agent, branch `main`.\nEvery contributor (human or agent) must read this before working on this repo.\n\n## Repository\n\n- **Never set git identity for commits to this repo's history.** Agents must not set\n  `user.name`/`user.email` (config or `-c`) or `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/\n  `GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` for commits that land in this repository.\n  Those commits carry the identity of the ambient git config. If such a commit fails for a\n  missing identity, report it instead of adding config. Allowed: the `*_DATE` variables\n  (the golden corpus pins them for reproducibility), throwaway temp repos created by\n  tests, and the release automation's bot identity.\n- **Never add `Co-authored-by` trailers** — not in commit messages, not in squash\n  suggestions, not as attribution for work merged from branches. A PR's commits carry\n  one identity: the ambient git config's. Fabricated or hand-written trailers (including\n  noreply forms) misattribute commits to unrelated GitHub accounts.\n- The repo is PrimeIntellect-ai/prime-agent; the Rust implementation lives on the `main` branch.\n- PRs go to the org repo with base `main`:\n  `gh pr create --repo PrimeIntellect-ai/prime-agent --base main`.\n- CI runs on the org's billing: `.github/workflows/continuous.yml` on `main` pushes and\n  `release.yml` on version tags.\n- Parity ground truth is unchanged: a read-only checkout of the TS implementation (this\n  repo at tag `v0.9.8`, the last TS release before the Rust port merged to `main`). Clone\n  it to `~/prime-agent`, the conventional location the parity scripts and code fall back\n  to; tooling that honors an override reads `PA_TS_REFERENCE`.\n\n## Style and structure\n\n- Workspace crates are prefixed `pa-`. The hard ownership rules: one owned area per crate,\n  pa-types is the only shared crate, cycle-free dependency direction, minimal public APIs,\n  no god-modules. The dependency direction is pinned in the Crates table below; each crate's\n  README.md states its scope, non-goals, and public API surface.\n- Prefer private modules with an explicitly exported public crate API. Internals are `pub(crate)`.\n- Aim for files under 2,000 lines, tests included. The 2,000-2,100 range is a soft review\n  signal, not a merge limit: when adding to an already-large file, consider splitting by\n  responsibility rather than growing it further. Move related tests and docs with extracted code.\n- Name modules for what they own, not `utils` or `common`. Follow existing structure: in\n  `crates/pa-core/src/kernel/manager/`, `mod.rs` connects `execution.rs`, `requests.rs`, and\n  `teardown.rs`; put a new kernel-manager concern beside them. In\n  `crates/pa-core/src/cron/store/`, `mod.rs` connects `heartbeat.rs`, `jobs.rs`, and\n  `session_artifacts.rs`; keep storage work there rather than growing the scheduler.\n- Inline format args: always prefer `format!(\"{x}\")` over positional.\n- Collapse if statements per clippy::collapsible_if.\n- Prefer method references over closures per clippy::redundant_closure_for_method_calls.\n- Make `match` statements exhaustive; avoid wildcard arms.\n- New traits need doc comments explaining their role and how implementations are expected to behave.\n- No opaque positional `bool`/`Option` parameters (`foo(false)` is unreadable). Prefer enums,\n  named methods, or newtypes. If you must pass an opaque literal by position, use an exact\n  `/*param_name*/` comment matching the callee signature.\n- Prefer native RPITIT trait methods with explicit `Send` bounds\n  (`fn foo(&self) -> impl Future<Output = T> + Send;`) over `#[async_trait]` or\n  `#[allow(async_fn_in_trait)]`. Implementations may use `async fn` when they satisfy the contract.\n- No single-use helper methods. Do not create a helper referenced only once.\n- Instrument async work at the definition (`#[tracing::instrument(...)]`), not with\n  `.instrument(...)` at call sites. Check whether the callee is already instrumented first.\n\n## Change hygiene\n\n- One logical change per PR. Fixes ride with the change that introduced them when possible; a PR\n  that mixes a feature with unrelated lint fixes or refactors hides both from review.\n- If you change dependencies (`Cargo.toml`), regenerate/commit `Cargo.lock` in the same change.\n  A new dependency is an architectural change: state in the PR why the existing crates cannot\n  host the functionality, and `make deny` must stay clean for it.\n- If a change starts forcing edits across many crate internals, stop and fix the boundary instead.\n\n## Tests\n\n- Prefer whole-object equality comparisons over field-by-field checks.\n- Do not add tests for statically defined values.\n- Do not add negative tests for logic that was removed.\n- Bug fixes need a regression test that fails without the fix.\n- Verifiers over self-assessment: tmux user-level tests, differential tests against the TS binary\n  on PATH, golden corpora replayed against real captured data. No lane merges without its verifier\n  passing, rerun by the reviewer where feasible.\n- Tests must wait for observable readiness, not fixed sleeps or retry-to-green loops. If a\n  test must be disabled, give a reason at the test. Use isolated ports and temporary paths, and\n  restore shared state. Run focused tests when changing their behavior.\n\n## Lint discipline\n\n- Zero-warning posture: the merge gates run fmt + clippy + tests at `-D warnings`, so a `warn`\n  lint is a merge blocker. Keep the enabled set deliberate and selective; enable a new lint family\n  only with every current site fixed in the same change.\n- Explain lint exceptions next to the `#[allow(...)]` or workspace configuration; keep\n  exceptions narrow. Advisory ignores in `deny.toml` need a reason and review date.\n\n## Performance and the critical path\n\nThe UI critical path is paint-latency-critical. First paint, and every\nframe the user waits on, must never block on network, disk sync, or\nbackground bookkeeping. The launch benchmarks measure this surface\n(cold/warm ready, first paint); a merge that regresses them undoes the\nproduct's core claim.\n\nRules:\n\n- Nothing user-visible awaits the network. Any HTTP/socket call on a\n  render path (telemetry, catalog fetch, update check) runs on a\n  background worker; the paint path hands the work off and returns\n  immediately. Delivery semantics (timeout, retry, ordering) live with\n  the worker, not the caller.\n- Telemetry is fire-and-forget from user-facing code. `pa-telemetry`'s\n  background worker owns delivery end to end; no startup, session\n  create, tab open, or first-render path may hold a flush or await a\n  sink.\n- Fire-and-forget boundaries need a red-first test: a hanging sink\n  (one that never replies) must not delay paint. The test fails if any\n  await on the critical path reaches the worker's delivery.\n- Tests that mock a sink or run offline cannot prove the above (the\n  benchmark's mock hides the POST). The regression test with a hanging\n  sink is the required verifier.\n\nExample (the #3288 regression this rule exists to prevent): the\ntelemetry startup flush was awaited on the interactive launch path, so\nthe analytics POST — a real HTTPS round-trip, ~157 ms — ran before the\nfirst frame. Every CI check passed because tests set DO_NOT_TRACK=1 and\nthe benchmark mocked the provider offline; only real-network launches\npaid the cost. The fix moved the flush to the background worker and\nadded `the_startup_flush_never_blocks_the_first_frame` (a hanging sink\nmust not delay paint) as the permanent guard. Any change touching the\nlaunch path must keep that test red-first.\n\n\n## Merge gates\n\n- `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`,\n  `cargo test --workspace` must pass before every merge. Run `make check` — the local mirror of\n  the same gates; CI runs on the org's billing (`.github/workflows/continuous.yml` on `main`\n  pushes; `release.yml` on version tags). The PR-only codebase-health check reports growth\n  past 2,000 lines as review guidance; it never blocks a merge.\n- **Parity-diff evidence is a merge gate** (the port's definition, not optional polish): every PR\n  that touches a user-visible surface must include a \"parity-diff evidence\" section in its\n  description showing the TS-binary comparison for what it changed: (1) rendered output —\n  frame-diff vs the TS binary;\n  (2) interactive behavior — the same input handled identically (keys, mouse, timing); \n  (3) wire parity — byte-compare the TS daemon's traffic for protocol changes; (4) user-visible\n  invariants — every user action produces the same visible reaction as TS (`/compact` shows\n  started+completed; `/model` shows the selector; a refinement shows its decoration). A feature\n  that \"works\" but was never diffed against the TS binary does not pass review. If TS shows it,\n  Rust shows it identically; if Rust shows something TS does not, that is also a parity bug.\n- PRs must state ownership compliance (crate README scope/non-goals/public API, dependency\n  direction) and classify the change: internals, new `pub` surface, or a new\n  dependency/cross-crate re-export. The latter two are architectural changes — an innocent-looking\n  `pub use` is a very simple way to break encapsulation.\n- The compiled fallback model catalog `crates/pa-ai/src/models_generated.rs` is\n  hand-maintained Rust mirroring the TS `packages/ai/src/models.generated.ts` object\n  literal — edit it by hand, exactly like its TS source (there is no generator). The\n  parity fixture `crates/pa-models/tests/fixtures/catalog.v1.json` refreshes with\n  `scripts/generate-catalog-fixture.py`. Bulk data files are exempt from the size guidance.\n\n## Adoption telemetry\n\nEvery user-visible feature ships its adoption telemetry event in the same PR as the feature:\nthe event name + properties join the versioned schema (`pa-telemetry`), and a\nseam emits it from day one. Telemetry properties never carry prompt, session, or file content\n(primitives only; see `pa-telemetry`); delivery is fire-and-forget from user-facing code\n(see Performance and the critical path).\n\n## Branding\n\nThe product is Prime Agent - we are not a pi fork. Scrub \"pi\"/\"pi-mono\"/\"pi-ai\"/\n\"Prime Intellect\"-style naming from all user-visible surfaces (docs, READMEs,\nCLI help text, error messages, splash/onboarding strings, keybinding hints, TUI\nlabels, and code comments that quote user-facing strings); brand everything\nPrime Agent. Audit with a repo-wide grep and classify every hit (user-visible\nvs wire-internal vs comment) before scrubbing, and list the preserved wire\nidentifiers in the PR body so the reviewer can verify none were wrongly scrubbed.\n\nEXPLICIT EXCEPTION: wire-protocol identifiers that must stay byte-compatible with the TS product (e.g. the PI_PACKAGE_DIR env var, settings keys, provider IDs like prime-inference, harness _meta namespaces like ai.primeintellect.prime-agent, lockfile names) stay until/unless the TS side renames them — PARITY BEATS BRANDING ON THE WIRE.\n\n\n\n## Surface contract (must not change)\n\n- Tools exposed to the model: `bash`, `edit`, `python_repl` (internal helpers: `rename`, `stdout`).\n- RLM kernel API in the persistent Python REPL: `rlm.spawn/find_models/collect/list_subagents/delete_subagent/create_session/progress_note`, `rlm.harness` CRUD, `agent_message.send`, `agent_observe`, `compact`, `goal`, `refine`, `attach_image`, skills (markdown + Python) per the skill contract in the base system prompt.\n- System prompt structure: layered — cache-stable static layer files (core harness description with the full API surface, mandatory usage rules, opinionated guidelines, per-model additions from the model-prompts TOML rule map) followed by one dynamic tail (packages, project context, skills inventory, MCP servers, environment, session role); the harness digest stays a separate `[harness-digest]` user message. `prime-agent prompt` dumps the assembled prompt with its layer breakdown.\n- CLI shape: `prime-agent` with the same commands/flags as the TS product; headless modes (RPC/daemon/session-worker) with identical behavior.\n\n## Crates\n\nOne owned area per crate; `pa-types` is the only shared vocabulary crate.\nDependencies flow from the composition root toward lower crates, never back upward.\nThe table summarizes each crate's current direct workspace dependencies:\n\n| Crate | Purpose | Direct workspace dependencies |\n| --- | --- | --- |\n| `pa-types` | Shared wire and domain types | none |\n| `pa-telemetry` | Events and sinks | none |\n| `pa-agent` | Provider-independent agent loop | none |\n| `pa-ai` | Providers, model registry, streaming | `pa-types` |\n| `pa-models` | Live model catalog and transport | `pa-ai`, `pa-types` |\n| `pa-core` | Session engine, tools, skills, kernel, settings | `pa-types`, `pa-ai`, `pa-models`, `pa-agent`, `pa-telemetry` |\n| `pa-daemon` | Supervisor, workers, wire protocol | `pa-types`, `pa-core`, `pa-agent`, `pa-ai`, `pa-telemetry`, `pa-models` |\n| `pa-tui` | Terminal UI, daemon-wire client | `pa-types` |\n| `pa-cli` | `prime-agent` binary, composition root | `pa-types`, `pa-core`, `pa-ai`, `pa-agent`, `pa-daemon`, `pa-tui`, `pa-telemetry` |\n| `pa-perf` | Performance corpora + pty bench harness (dev/CI tooling, never shipped) | `pa-types`, `pa-core`, `pa-daemon` |\n\nLayering rules:\n\n- Dependencies only point from higher crates to lower crates shown above. No cycles or\n  reverse edges. The leaf crates are peers; add only the dependencies needed for their work.\n  Shared wire/domain vocabulary belongs in `pa-types`, not in a higher crate or a duplicate.\n- `pa-tui` renders from wire types and events; it does not link the session engine.\n- `pa-cli` is a composition root: it wires crates together and contains no business logic.\n\n## Reliability model\n\n- The daemon is a supervisor: it spawns one worker process per active session instead of hosting sessions in-process. Workers are supervised, restarted with backoff, and sessions persist on disk (append-only JSONL, same layout as `~/.prime/agent/sessions`) so reattach works even if the supervisor restarts.\n- No stubs, no `todo!()`, no swallowed errors (`anyhow` bubbling to UI is fine).\n\n## References\n\n- Cursor Bugbot's PR review rules (`.cursor/BUGBOT.md`) mirror the standards in this file - update both whenever either changes.\n","isInternal":false,"tokens":3373,"sizeBytes":14330},{"name":"SKILL.md","path":"skills/agent-message/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/agent-message/SKILL.md","title":"agent-message","category":"anthropic-skill","format":"markdown","content":"---\nname: agent-message\ndescription: Message an agent's parent, siblings, or direct children through the daemon. Discover reachable agents with agent_observe.list_agents, then send direct text without spoofing sender identity.\n---\n\n# Agent Message\n\nSend direct messages within the current agent's nuclear family through the\nlocal daemon: parent, siblings, and direct children only. Roots are siblings.\nThe daemon derives your sender identity from the current session; do not try\nto include a `from` field.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    receipt = await agent_message.send(\n        \"Please inspect the latest result.\",\n        receiver_role=\"child\",\n        receiver_name=child.session_name,\n    )\n    # Keep the child until this follow-up finishes so its result remains observable.\n```\n\n## API\n\n- `await agent_observe.list_agents()` (agent-observe skill) is the roster: it\n  lists the parent, siblings, and children this skill can reach, active or not,\n  with the `relationship` and `sessionName` that `send` takes as\n  `receiver_role` and `receiver_name`.\n- `await agent_message.send(message, receiver_role=\"parent\" | \"sibling\" | \"child\", receiver_name=None)` — sends one direct\n  text message to one family member. Sending to an inactive or idle completed\n  subagent wakes it and starts an ordinary follow-up turn in that same session\n  and context.\n  The child remains available only until its parent session closes. The daemon\n  resolves `receiver_role` within the current agent family; `receiver_name` is\n  required for siblings and children and omitted for the unique parent.\n  `send(\"all\", message)` broadcasts only to the family roster and returns\n  `{receipts: [...]}` in roster order; successful entries are ordinary receipts\n  and failed entries contain the target id and a short `error`. One failed delivery\n  does not reject successful deliveries. Messages always use steering delivery so\n  a busy target sees them during its active run. Returns a receipt with a\n  `deliveryStatus` field: `\"delivered\"` means the message reached an idle target's\n  context; `\"queued\"` means a steering message was accepted and will deliver when\n  the target's current work allows (`send` does not block waiting for that).\n  Delivered receipts carry `deliveredAt`, queued receipts carry `queuedAt`.\n\n## Safety\n\n- Do not delete a child immediately after `send`: delivered follow-ups may still\n  be running and queued receipts have not run yet. Wait until observation shows\n  the child is idle and its context is no longer needed before calling\n  `await rlm.delete_subagent(child)`.\n- Reach is limited to parent, siblings, and direct children; relay through an\n  intermediate child instead of messaging grandchildren or cousins directly.\n- Sender identity is daemon-derived and cannot be spoofed from Python.\n- The daemon enforces message size, rate, and pending-queue limits before\n  accepting delivery.\n","frontmatter":{"name":"agent-message","description":"Message an agent's parent, siblings, or direct children through the daemon. Discover reachable agents with agent_observe.list_agents, then send direct text without spoofing sender identity."},"isInternal":false,"tokens":654,"sizeBytes":3050},{"name":"SKILL.md","path":"skills/agent-observe/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/agent-observe/SKILL.md","title":"agent-observe","category":"anthropic-skill","format":"markdown","content":"---\nname: agent-observe\ndescription: Read-only roster and observation of an agent's parent, siblings, and direct children. Use to discover reachable agents and to inspect family status and bounded recent-message previews without mutating sessions.\n---\n\n# Agent Observe\n\nObserve the current agent's nuclear family through the local daemon: parent,\nsiblings, direct children, and self. `list_agents` is the one family roster and\ncovers every member `agent_message.send` can reach. `get_agent` also returns an\ninactive child's roster row. `recent_messages` reads live sessions only; it\ndoes not rehydrate an inactive member. They cannot read a root sibling that has\nno live session in this worker.\nThis skill is read-only: it can list family sessions, inspect one session, and fetch\nbounded recent message previews. It cannot prompt, steer, clear, kill, rename, or\notherwise mutate another session.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    worker = await agent_observe.get_agent(child.session_name)\n    recent = await agent_observe.recent_messages(child.session_name, limit=6)\n    # Deletion is a parent-owned RLM operation, not an observe mutation:\n    await rlm.delete_subagent(child)\n```\n\n## API\n\n- `await agent_observe.list_agents()` returns `current` (the calling agent's\n  own row) and `agents` (the family: parent, siblings, and direct children,\n  active or not; the caller is excluded from `agents`). Each row carries\n  `sessionId`, optional `sessionName`, `relationship`\n  (`parent`/`sibling`/`child`), `status` (`running`/`idle` for live sessions,\n  `inactive` without one), the live `activity` (`tool`/`model`/`compacting`/\n  `busy`/`user`/`idle`), `isSessionActive`, the counts known\n  for it (`messageCount`, `queuedCount`, `attachedClients`), `cwd` when the\n  roster row carries it, the parent edges (`parentActiveSessionId`,\n  `parentSessionId`) and `rlmChildId` for subagents, and `firstMessage`\n  (capped at 240 chars) for an inactive child. A member with no live session\n  has no `activeSessionId` and no live detail; address it with\n  `agent_message.send` using its `relationship` plus its `sessionName`, or its\n  `sessionId` when the member has no name. For direct children,\n  `await rlm.list_subagents()` also exposes parent-owned lifecycle handles.\n- `await agent_observe.get_agent(target)` returns `agent`, where `agent`\n  contains one agent summary (the same shape as the roster rows, including a\n  passive child's row). `target` is resolved like other live-session\n  selectors: active id, session id or name, or an unambiguous id suffix.\n- `await agent_observe.recent_messages(target, limit=8, max_chars=800)`\n  returns `agent` (the target's summary), `messages` (up to `limit` recent\n  bounded previews), the clamped `limit` and `maxChars`, and `truncated`\n  (true when older messages exist beyond the returned window). `limit` must be\n  1-50, and `max_chars` must be 80-2000. The target must be a live family\n  member: a member with no live session errors instead of hydrating.\n\n## Safety\n\n- This skill is read-only and exposes no mutation commands.\n- Targets outside the nuclear family are rejected; transcript reads follow the\n  same family rule as messaging.\n- Message access is bounded by count and per-message character limit.\n- Prefer status and recent previews for orchestration. Ask the user before\n  using observed context to steer or message another session.\n","frontmatter":{"name":"agent-observe","description":"Read-only roster and observation of an agent's parent, siblings, and direct children. Use to discover reachable agents and to inspect family status and bounded recent-message previews without mutating sessions."},"isInternal":false,"tokens":848,"sizeBytes":3533},{"name":"SKILL.md","path":"skills/attach-image/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/attach-image/SKILL.md","title":"attach-image","category":"anthropic-skill","format":"markdown","content":"---\nname: attach-image\ndescription: Load an on-disk image (PNG, JPEG, GIF, WebP) into the model's context as a viewable attachment so the model can directly SEE it — for screenshots, diagrams, charts, photos, or scanned pages. Use this when you need to perceive an image's visual contents. Requires a vision-capable model; errors clearly otherwise.\n---\n\n# Attach Image\n\nLoad on-disk images into the model's context as multimodal attachments. The\nimage is sent to the model the same way a pasted image is, so the model can\nactually look at it.\n\n## When to use this\n\n- The user points at an image file and wants you to look at it.\n- You need to read text, a chart, a diagram, or a layout from an image.\n- A screenshot needs visual interpretation.\n\n## When NOT to use this\n\nFor *programmatic* work on an image — measuring pixels, cropping, resizing,\ncomputing a hash, comparing files byte-by-byte — open it in the kernel with a\nlibrary instead:\n\n```python\nfrom PIL import Image\nimg = Image.open(\"diagram.png\")\nprint(img.size)\n```\n\nThat path does not put the image in the model's context; it only lets you\ncompute over it. Use `attach_image` when you need to *see* the image.\n\n## Usage\n\nCall the prepared `attach_image` import directly in the Python kernel:\n\n```python\nprint(await attach_image(\"diagram.png\"))\nprint(await attach_image(\"a.png\", \"b.jpg\"))\n```\n\nThe skill automatically resizes and compresses large images before loading them\ninto context. Animated images that need compression are flattened to their first\nframe. Transparent images that need compression are composited onto a neutral\ngray background. Extremely large images are rejected by pixel count before full\nprocessing. The original file is left untouched.\n\nSupported formats: PNG, JPEG, GIF, WebP. The skill errors if a file is not a\nsupported image, or if the current model is not vision-capable.\n","frontmatter":{"name":"attach-image","description":"Load an on-disk image (PNG, JPEG, GIF, WebP) into the model's context as a viewable attachment so the model can directly SEE it — for screenshots, diagrams, charts, photos, or scanned pages. Use this when you need to perceive an image's visual contents. Requires a vision-capable model; errors clearly otherwise."},"isInternal":false,"tokens":425,"sizeBytes":1871},{"name":"SKILL.md","path":"skills/compact/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/compact/SKILL.md","title":"compact","category":"anthropic-skill","format":"markdown","content":"---\nname: compact\ndescription: Check context usage and compact the conversation from the Python REPL. Use when context is filling up and substantial work remains, so the session is summarized and you keep working instead of stopping early.\n---\n\n# Compact\n\nCompaction replaces older conversation history with a dense summary, freeing\ncontext so long-running work can continue. The implementation lives in the\nhost (the same one behind the user's `/compact` command); this skill is the\nkernel-side interface to it. Call it directly from the Python REPL:\n\n```python\nawait compact.status()\nawait compact.run()\nawait compact.run(\"keep the failing test names and the migration checklist\")\n```\n\n## API\n\n- `await compact.status()` — current context usage as a dict: `tokens`,\n  `context_window`, and `percent` (`None` right after a compaction until the\n  next model response), plus `scheduled` (whether a requested compaction is\n  already pending).\n- `await compact.run(instructions=None)` — schedule compaction. Returns\n  `{\"scheduled\": True}`, or `{\"scheduled\": False, \"reason\": ...}` when there\n  is nothing to compact yet. Optional `instructions` focus the summary on\n  what matters for the remaining work.\n\n## Rules\n\n- Compaction never runs mid-cell. A scheduled compaction runs when the\n  current turn ends; the harness then resumes you automatically with the\n  summary plus recent messages, and you continue the task.\n- The Python kernel persists through compaction — variables, imports, and\n  helpers you defined all remain available.\n- Compact at a natural boundary when context usage is high and substantial\n  work remains, instead of becoming terse or returning to the user early.\n  Check `await compact.status()` when unsure.\n- One request per turn is enough; calling `run` again before the turn ends\n  only updates the instructions.\n","frontmatter":{"name":"compact","description":"Check context usage and compact the conversation from the Python REPL. Use when context is filling up and substantial work remains, so the session is summarized and you keep working instead of stopping early."},"isInternal":false,"tokens":389,"sizeBytes":1844},{"name":"SKILL.md","path":"skills/edit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/edit/SKILL.md","title":"edit","category":"anthropic-skill","format":"markdown","content":"---\nname: edit\ndescription: Replace an exact, unique string in an existing file. Use for targeted single-occurrence edits to files from the Python kernel instead of rewriting the whole file.\n---\n\n# Edit\n\nMake a targeted edit to an existing file by replacing one exact, unique\noccurrence of a string. `old_str` must appear exactly once in the file.\n\nCall directly from the kernel:\n\n    await edit(path=\"pkg/file.py\", old_str=old, new_str=new)\n\nUse exact old/new strings. If the text contains triple double quotes, use\ntriple single-quoted variables (`old = '''...'''`) or build `old`/`new` from\ninspected file slices. Returns a short confirmation; raises if `old_str` is\nmissing or matches more than once (widen the snippet to make it unique).\n\nOr from a shell cell:\n\n    !edit --path pkg/file.py --old-str \"...\" --new-str \"...\"\n","frontmatter":{"name":"edit","description":"Replace an exact, unique string in an existing file. Use for targeted single-occurrence edits to files from the Python kernel instead of rewriting the whole file."},"isInternal":false,"tokens":198,"sizeBytes":828},{"name":"SKILL.md","path":"skills/factory/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/factory/SKILL.md","title":"factory","category":"anthropic-skill","format":"markdown","content":"---\nname: factory\ndescription: Run state-machine workflows of spawned child agents: store a validated machine or dag spec as a continual-harness factory entry (rlm.harness.create_factory), then run, watch, stop, and resume it through rlm.factory. For the full authoring reference and API guide, call rlm.factory.help() in the kernel.\n---\n\n# Factory\n\nThe factory runs state-machine workflows of spawned child agents. A stored\nfactory entry — harness kind `factory`, written with\n`rlm.harness.create_factory` — declares the machine: states, each backed by\na subagent spec, plus guarded transitions between them. The spec validates\nat write time (machine form, or `dag` sugar that compiles to one; pass\nexactly one), and an invalid spec is never stored.\n`await rlm.factory.run('<spec_id>')` then spawns each state's subagent as an\nordinary child, feeds captured outputs into the successors' prompts, and\ndrives the run to quiescence in a background kernel task — the call\nreturns immediately and the run continues after the model turn ends. Use\nit when a workflow needs shape: fan-out, bounded loops (review/fix until a\nverdict approves), joins, or one child per list item.\n\n**For the full authoring reference and API guide — states, ports, guards,\njoins, foreach, residents, budgets and policies, and the `rlm.factory`\nrun/status/stop/resume/graph/watch calls with worked examples — call\n`rlm.factory.help()` in the kernel.** The guide lands with the factory-core\nPR; on builds without it, the module docstring in\n`prime-agent-runtime/src/rlm/factory.py` is the source of truth.\n\n## The opt-in gate\n\nThe factory ships disabled. `rlm.factory.help()` answers while it is off\n(the authoring guide stays readable before opting in), but every other\n`rlm.factory` call and every factory harness write refuses with one\nmessage: `the factory is disabled; run /factory on to enable it`. The\nuser turns it on with `/factory on` in the client (`/factory off`\ndisables it again — refused while the session still has live runs, and\non a lane-advertising client while the live-run count cannot be read, so\nan active factory never loses its stop path, `/factory status` reports\nit), which persists the\n`factory.enabled` setting in the agent dir's settings.json — the same\nsetting the daemon's `factory_activity` lane advertisement reads, so the\nTUI's factory dock group and page surface only on a client started while\nthe factory is enabled. If a call refuses with that message, tell the\nuser to run `/factory on` and restart the client.\n\n## Discovering machines\n\n- The machine library: machines are `MACHINE.md` files, one directory\n  per machine — the bundled seeds ship inside the runtime package (wheel\n  package data, `rlm/machines/<name>/MACHINE.md`; `PRIME_AGENT_MACHINES_DIR`\n  redirects that level at a team directory), and the personal library\n  lives under the agent dir. `prime-agent factory list | import | export`\n  manages them. The seeds are `builder`, `pr-manager`, and `review-sweep`.\n- The TUI factory page: the activity dock's `⚙ N factory` group (Enter or\n  click) opens one live diagram per run, newest run first. The up/down\n  arrows move the selection, Enter opens the selected run's action rows\n  (stop, or resume while it is paused — arrows to walk, Enter to run),\n  Esc closes.\n","isInternal":false,"tokens":774,"sizeBytes":3308},{"name":"SKILL.md","path":"skills/goal/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/goal/SKILL.md","title":"goal","category":"anthropic-skill","format":"markdown","content":"---\nname: goal\ndescription: Manage the persistent thread goal from the Python REPL. Use to read goal status and budget usage, to start a goal when the user explicitly asks for one, or to mark the active goal complete once its objective is fully achieved.\n---\n\n# Goal\n\nThe thread goal is a persistent objective the harness keeps re-prompting you to\npursue across turns until it is complete. Goal state (status, token budget,\nusage accounting) lives in the host; this skill is the kernel-side interface to\nit. Call it directly from the Python REPL:\n\n```python\nawait goal.get()\nawait goal.create(\"ship the release notes\")\n# Only pass token_budget when the user explicitly asks for one:\n# await goal.create(\"ship the release notes\", token_budget=200000)\nawait goal.complete()\n```\n\n## API\n\n- `await goal.get()` — current goal as a dict: `goal` (or `None` when no goal\n  is set), `remaining_tokens`, and `completion_budget_report`. The `goal` dict\n  carries `objective`, `status`, `token_budget`, `tokens_used`,\n  `time_used_seconds`, and timestamps.\n- `await goal.create(objective, token_budget=None)` — start a new active goal.\n  Fails while a goal is still pending (active, paused, or budget-limited); a\n  completed or errored goal is replaced by the new one. Only create a goal when\n  the user or system/developer instructions explicitly ask for a persistent\n  long-running goal; do not infer goals from ordinary tasks. Set `token_budget`\n  only when an explicit token budget is requested.\n- `await goal.complete()` — mark the existing goal achieved. Use only when the\n  objective has actually been achieved and no required work remains; do not\n  call it merely because the budget is nearly exhausted or because you are\n  stopping work. When the result includes a `completion_budget_report`, report\n  that final usage to the user.\n\n## Rules\n\n- Goal status transitions other than completion (pause, resume, clear,\n  budget-limiting) are controlled by the user and the host; there is no API for\n  them here.\n- When an active goal is actually complete, call `await goal.complete()`; do\n  not merely say it is done — the harness keeps continuing the goal until the\n  completion call arrives.\n","frontmatter":{"name":"goal","description":"Manage the persistent thread goal from the Python REPL. Use to read goal status and budget usage, to start a goal when the user explicitly asks for one, or to mark the active goal complete once its objective is fully achieved."},"isInternal":false,"tokens":496,"sizeBytes":2194},{"name":"SKILL.md","path":"skills/mcp/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/mcp/SKILL.md","title":"mcp","category":"anthropic-skill","format":"markdown","content":"---\nname: mcp\ndescription: Use external MCP services generically from Python - search the supported-service catalog, inspect the user's connections, discover live tool schemas, and call tools on any connection (Notion, Linear, Slack, and the rest of the catalog) without per-service packages.\n---\n\n# MCP Services\n\nEvery external service reachable over MCP uses the same pre-imported `mcp`\nmodule. Adding a service is data (a catalog entry plus a user login), never a\nnew Python package, and there are no per-service skills to read.\n\n## Inventory: what can I use?\n\n```python\n# Supported catalog, one bounded page. More pages exist while nextCursor is not None.\npage = await mcp.list_plugins(connection_status=\"not_connected\", limit=50)\nresults = await mcp.search_plugins(\"notion\")          # bounded search\npage = await mcp.list_plugins()                       # default: first 50 entries\n\n# The user's actual connections. connectionId is the dispatch id everywhere below.\nconnections = await mcp.list_connections()\n```\n\nCatalog entries carry `connectionStatus` (`connected`, `pending`,\n`not_connected`, `setup_required`, `disabled`, `error`), `connectable`, and\nwhen connected the `connectionIds` you dispatch on. `connected` means a\nverified MCP handshake, not just stored credentials; `pending` means\ncredentials exist but verification hasn't run or succeeded yet. Entries may\nalso carry `setupHint` (why a service isn't connectable yet), `unverified`\n(imported but not vetted), `verifiedAt`/`toolCount`, and `connectionIds`\n(empty when not dispatchable). Entries with `setup_required` need a developer\napp or API key first — say so honestly instead of promising one-click.\n\n## Recommend, never connect\n\nIf a task would benefit from an unconnected service, name the real catalog\nentry (e.g. \"Connecting Notion would let me search your workspace directly\")\nand tell the user to open `/plugins` (or run `/mcp login <service>`) to connect.\nRecommendations and catalog lookups never install anything, open a browser,\nuse credentials, or request extra scopes. There is no agent-initiated connect\ncall in this slice; if the user connects mid-task, the connection activates on\nthe next call without a reload.\n\n## Discover, then call\n\n```python\n# Live tool metadata is cached per connection; schemas come from the server.\ntools = await mcp.search_tools(\"search workspace documents\", connection_id=\"notion\")\ntool = await mcp.describe_tool(\"notion\", \"notion-search\")   # {name, description, inputSchema}\ntools = await mcp.list_tools(\"notion\")                     # full tool list with schemas\n\nresult = await mcp.call_tool(\"notion\", \"notion-search\", {\"query\": \"roadmap\"})\n```\n\n- Discover before calling: don't assume tool names or arguments; read the\n  `inputSchema` with `describe_tool` and construct matching arguments.\n- `list_tools` returns the complete inventory or raises — never a silent\n  partial list. Returned schemas are isolated copies; mutate them freely.\n- `search_tools` without a `connection_id` searches at most 8 connections the\n  host reports as connected and reports its scope: `searched`, `unavailable`\n  (per-connection failures as fixed, redaction-safe summaries), and\n  `truncated` (narrow the query or pick a connection when it is set — the\n  result never claims to be exhaustive).\n- Prefer narrow catalog searches over paging the whole catalog; don't dump all\n  schemas into context.\n- Results are already-parsed Python (a `dict` for structured output, otherwise\n  a string). No `json.loads` needed.\n\n## Errors and permissions\n\n- `PermissionError` — the tool is excluded by the user's `enabledTools` /\n  `disabledTools` policy. Don't retry; tell the user.\n- `KeyError` — the tool or connection doesn't exist. Re-check with\n  `list_tools` / `list_connections`; tools can change across sessions.\n- `McpDiscoveryError` — the server's tool listing couldn't complete honestly\n  (broken pagination). No partial inventory is published; re-run, and ask the\n  user to reconnect if it persists.\n- `RuntimeError` — credentials are not available (`McpCredentialsUnavailable`:\n  ask the user to connect via `/plugins` or `/mcp login <service>`, never via\n  environment variables), a refresh failed, or the host bridge is unavailable.\n- `McpToolError` — the server flagged the call as an error. Surface the\n  message; don't blindly retry a write that may have already happened.\n\nCredentials never appear in inventory results, tool schemas, or errors.\n","frontmatter":{"name":"mcp","description":"Use external MCP services generically from Python - search the supported-service catalog, inspect the user's connections, discover live tool schemas, and call tools on any connection (Notion, Linear, Slack, and the rest of the catalog) without per-service packages."},"isInternal":false,"tokens":1010,"sizeBytes":4471},{"name":"compute.md","path":"skills/prime-intellect/references/compute.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/prime-intellect/references/compute.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Compute & Storage\n\nPrime Intellect aggregates GPU capacity across providers: rent single GPU pods on demand or deploy multi-node clusters, with persistent network-attached storage.\n\nLive docs: `cli-reference/check-gpu-availability.md`, `cli-reference/provision-gpu.md`, `cli-reference/managing-disks.md`, `tutorials-multi-node-cluster/deploy-multi-node.md`, `tutorials-storage/create-persistent-storage.md` under https://docs.primeintellect.ai/\n\n## GPU Availability\n\n```bash\nprime availability list                        # all GPUs with pricing\nprime availability list --gpu-type H100_80GB   # filter by GPU type\n```\n\n## Pods (single instances)\n\n```bash\nprime config set-ssh-key-path   # one-time: SSH key for pod access (generate on the dashboard profile page)\nprime pods create               # interactive provisioning from availability data\nprime pods list\nprime pods ssh <pod-id>\n```\n\nPods support custom Docker images (`tutorials-on-demand-cloud/deploy-custom-docker-image.md`). Monitor, terminate, and inspect pods from the CLI or the dashboard.\n\n## Multi-Node Clusters\n\nDeploy multi-node clusters (with optional Slurm orchestration) from the platform; see `tutorials-multi-node-cluster/deploy-multi-node.md` and `tutorials-multi-node-cluster/slurm-orchestration.md`. Cluster monitoring guidance lives at `tutorials-reserved-clusters/monitoring.md`.\n\n## Storage\n\nPersistent disks outlive individual instances and can be attached to different instances as needed:\n\n- Create disks from the Storage tab of the Instances page (choose provider, datacenter, size), then attach them to pods or clusters.\n- Manage disks from the CLI as well — see `cli-reference/managing-disks.md`.\n- For multi-node shared and ephemeral storage patterns, see `tutorials-storage/cluster-storage.md`.\n\n## Teams\n\nManage team membership and run resources against team billing:\n\n```bash\nprime teams list\n```\n\nMost provisioning commands accept a `--team-id` flag; the REST API equivalent is the `X-Prime-Team-ID` header.\n","isInternal":false,"tokens":430,"sizeBytes":2001},{"name":"environments.md","path":"skills/prime-intellect/references/environments.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/prime-intellect/references/environments.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Environments, Evaluations & Training\n\nverifiers is Prime Intellect's Python library for LLM environments: packages that expose `load_environment` and bundle datasets, rollout logic, and reward rubrics. Environments power evaluations (local and hosted) and RL training (Hosted Training or self-managed prime-rl).\n\nLive docs: `verifiers/overview.md`, `tutorials-environments/getting-started.md`, `hosted-training/getting-started.md`, `prime-rl/overview.md` under https://docs.primeintellect.ai/ (append `.md` for raw markdown). Source: https://github.com/PrimeIntellect-ai/verifiers and https://github.com/PrimeIntellect-ai/prime-rl\n\n## Discovering Environments (Hub)\n\n```bash\nprime env list --search \"math\" --owner primeintellect --show-actions\nprime env list --tag tools --tag sandbox\nprime env list --mine\nprime env list --starred\nprime env info owner/name        # metadata, version, dependencies\nprime env status owner/name      # CI/action status\nprime env pull owner/name -t ./tmp-env   # pull source for inspection\nprime env install owner/name     # install locally\n```\n\nWhen picking candidates, prefer: `primeintellect`-owned, passing latest actions, updated within ~2 months, recent verifiers versions. Compare task type (single-turn, multi-turn, tool, sandbox, agent), reward type (binary, continuous, judge-based), and dependency/secret requirements.\n\n## Creating Environments\n\n```bash\nprime env init my-env --v1       # scaffold (add --with-harness for an explicit reusable harness)\nprime env install my-env\nprime eval run my-env -m openai/gpt-4.1-mini -n 5   # smoke test immediately\nprime env push                   # publish to the Hub\n```\n\nBuild guidance:\n\n- Define the task contract first: prompt shape, allowed tools, stop conditions, rubric outputs, metrics.\n- Prefer starting from an existing Hub environment (`prime env list --search`, then `prime env install owner/name`) over building from scratch.\n- v1 environments expose `load_environment(config: vf.EnvConfig) -> vf.Env`; Taskset + Harness environments additionally expose `load_taskset(config)` and optionally `load_harness(config)` with `load_environment` delegating through `vf.load_taskset`/`vf.load_harness`.\n- The environment must install, load, evaluate, and train without hidden setup.\n\n## Evaluations\n\n`prime eval run` is the canonical eval path. Runs save automatically (visible in the Evaluations tab and `prime eval view`); do not add `--skip-upload` unless the user explicitly asks.\n\n```bash\nprime eval run my-env -m openai/gpt-4.1-mini -n 5               # smoke\nprime eval run owner/env -m openai/gpt-4.1-mini -n 200 -r 3 --shuffle -s   # scaled\nprime eval run owner/env --hosted --follow                       # hosted, streaming logs\n```\n\n- Smoke-test first; scale only after a pass. Use `--shuffle` (seed defaults to 0; set `--shuffle-seed` for reproducible reports).\n- Hosted evals require the environment to be published (`prime env push`) and support TOML configs and temporary sandbox/tunnel permissions (`--allow-tunnel-access`).\n- Prime Inference models include estimated run cost in eval output automatically.\n- Keep reusable model endpoints as aliases in `configs/endpoints.toml` (fields: `endpoint_id`, `model`, `url`, key) and reference them with `-m <endpoint_id>`.\n\n## Training\n\nDefault to Hosted Training unless the user explicitly wants self-managed infrastructure.\n\n```bash\nprime lab setup                  # Lab workspace for environments, evals, GEPA, Hosted Training\nprime train models               # supported models, capacity, pricing\nprime train init                 # generate a training config\nprime train rl.toml              # launch the run\n```\n\n- Hosted Training launches from a CPU machine; no local GPUs needed.\n- Validate the environment with an eval before training (e.g. `-n 20 -r 3 -s`) and confirm reward diversity exists at baseline.\n- Self-managed path: `prime lab setup --prime-rl`, then follow prime-rl's own configs and launch commands. Treat prime-rl as a power-user path requiring local GPU access; see https://docs.primeintellect.ai/prime-rl/overview.md.\n\n## Model Family Choice\n\nAsk the user whether they want instruct or reasoning models before non-trivial runs:\n\n- Instruct (quick behavior checks): `gpt-4.1` series, `qwen3` instruct series.\n- Reasoning (harder probes, deeper coverage): `gpt-5` series, `qwen3` thinking series, `glm` series.\n","isInternal":false,"tokens":1033,"sizeBytes":4385},{"name":"inference.md","path":"skills/prime-intellect/references/inference.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/prime-intellect/references/inference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Prime Inference\n\nPrime Inference is an OpenAI-compatible API for frontier and open models, routed across providers and built for large-scale evaluations.\n\nLive docs: `inference/overview.md`, `inference/usage.md`, `inference/adapter-deployments.md`, `inference/troubleshooting.md` under https://docs.primeintellect.ai/\n\n## Setup\n\n1. Create an API key on https://app.primeintellect.ai (account settings → API Keys) with the **Inference** permission enabled — without it, requests fail with authentication errors.\n2. Export it:\n\n```bash\nexport PRIME_API_KEY=\"your-api-key-here\"\n```\n\n## Via the CLI (recommended for evaluations)\n\n```bash\nprime inference models                                   # list available models\nprime eval run gsm8k -m meta-llama/llama-3.1-70b-instruct -n 25   # evals route through Prime Inference\n```\n\nEval runs against Prime Inference models report estimated USD cost automatically.\n\n## Direct API (OpenAI-compatible)\n\nBase URL: `https://api.pinference.ai/api/v1`\n\n```python\nimport openai, os\n\nclient = openai.OpenAI(\n    api_key=os.environ[\"PRIME_API_KEY\"],\n    base_url=\"https://api.pinference.ai/api/v1\",\n)\nresponse = client.chat.completions.create(\n    model=\"meta-llama/llama-3.1-70b-instruct\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n```\n\nAnything that speaks the OpenAI API works — just point it at the base URL above. Streaming and advanced parameters are covered in `inference/usage.md`.\n\n## Teams & Adapters\n\n- Team billing: send the `X-Prime-Team-ID` header (find the ID via `prime teams list` or the Team Profile page) to use team credits instead of personal balance.\n- LoRA adapters trained with Hosted Training can be deployed and queried through the same OpenAI-compatible API (`inference/adapter-deployments.md`).\n","isInternal":false,"tokens":437,"sizeBytes":1777},{"name":"sandboxes.md","path":"skills/prime-intellect/references/sandboxes.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/prime-intellect/references/sandboxes.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Sandboxes & Tunnels\n\nPrime Sandboxes are disposable VM environments for running AI-generated or untrusted code in the cloud: isolated, fast to create, billed only while running (CPU $0.05/core/hr, memory $0.01/GB/hr, disk $0.001/GB/hr).\n\nLive docs: `sandboxes/overview.md`, `sandboxes/cli.md`, `sandboxes/sdk.md`, `sandboxes/images.md`, `sandboxes/tunnel.md` under https://docs.primeintellect.ai/\n\n## CLI Lifecycle\n\n```bash\nprime sandbox create python:3.11-slim --timeout-minutes 120   # any Docker image\nprime sandbox list\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox get <sandbox-id>\nprime sandbox delete <sandbox-id>\n```\n\nUseful create flags:\n\n```bash\nprime sandbox create python:3.11-slim \\\n  --name analytics-lab \\\n  --cpu-cores 2 --memory-gb 4 --disk-size-gb 20 \\\n  --timeout-minutes 240 \\\n  --idle-timeout-minutes 15 \\\n  --env APP_ENV=staging \\\n  --secret API_KEY=sk-abc123 \\\n  --yes\n```\n\n- `--timeout-minutes` caps total lifetime; `--idle-timeout-minutes` reaps the sandbox early when no exec/upload/download/file-read arrives (1 ≤ idle ≤ timeout ≤ 1440; for VM sandboxes, `timeout_minutes` may be negative to disable the lifetime deadline).\n- `--env` values are plain text; `--secret` values are encrypted at rest and obfuscated in output. Both become environment variables inside the sandbox.\n- Default start command keeps the sandbox idle, ready for `prime sandbox run`. To run your own process at boot, pass the command after `--` as separate tokens (no shell): `prime sandbox create python:3.11-slim -- python serve.py --port 8000`.\n- Outbound internet is on by default; restrict egress with network allow/deny lists (`prime sandbox network`, or `network_allowlist`/`network_denylist` in the SDK).\n- `--team-id` bills a team; `--yes` skips confirmation in automation.\n\nCustom images: build and push your own via Prime Images (`sandboxes/images.md`).\n\n## Python SDK\n\n`prime_sandboxes` ships `SandboxClient` (sync) and `AsyncSandboxClient` (async) with identical methods:\n\n```python\nfrom prime_sandboxes import SandboxClient, CreateSandboxRequest, APIClient\n\nclient = SandboxClient(APIClient())\nsandbox = client.create(CreateSandboxRequest(\n    name=\"sdk-demo\",\n    docker_image=\"python:3.11-slim\",\n    timeout_minutes=120,\n    environment_vars={\"LOG_LEVEL\": \"debug\"},\n    secrets={\"API_KEY\": \"sk-abc123\"},\n))\nclient.wait_for_creation(sandbox.id)\nresult = client.execute_command(sandbox.id, \"python -c 'print(42)'\")\nclient.upload_file(sandbox.id, \"/workspace/data.csv\", \"./data.csv\")\nclient.download_file(sandbox.id, \"/workspace/output.csv\", \"./output.csv\")\nclient.delete(sandbox.id)\n```\n\nAsync variant: `async with AsyncSandboxClient() as sandboxes: await sandboxes.create(...)` — same methods, useful for fanning out many sandboxes concurrently.\n\n## Tunnels\n\nPrime Tunnel exposes a local (or in-sandbox) service through a secure public HTTPS URL — for dev servers, webhooks, and sharing work in progress:\n\n```python\nfrom prime_tunnel import Tunnel\n\ntunnel = Tunnel(local_port=8000)\nawait tunnel.start()   # prints the public URL\n```\n\nHosted evaluations can create tunnels too: launch the run with `--allow-tunnel-access` (grants tunnel permission to the temporary `PRIME_API_KEY`), then use the same flow inside the hosted sandbox.\n","isInternal":false,"tokens":822,"sizeBytes":3276},{"name":"SKILL.md","path":"skills/prime-intellect/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/prime-intellect/SKILL.md","title":"prime-intellect","category":"anthropic-skill","format":"markdown","content":"---\nname: prime-intellect\ndescription: Work with Prime Intellect products via the prime CLI and Python SDKs - verifiers environments and the Environments Hub, evaluations (local and hosted), Hosted Training and prime-rl, code sandboxes, Prime Inference, GPU compute (pods and clusters), storage, and tunnels. Use when a task involves Prime Intellect, the prime CLI, verifiers, RL environments, evals, training, sandboxes, renting GPUs, Prime Inference models, or when the user asks what Prime Intellect is or what it offers.\n---\n\n# Prime Intellect\n\nPrime Intellect is an open superintelligence lab building open-source AGI infrastructure: a platform for RL environments, evaluations, post-training, inference, and globally distributed GPU compute. Prime Agent (this agent) is built by Prime Intellect, and the `prime` CLI is the default way to interface with every product below.\n\n## Product Map\n\n| Product | What it is | Details |\n|---|---|---|\n| verifiers | Python library for building LLM environments and evaluations | [environments.md](references/environments.md) |\n| Environments Hub | Platform library of community RL environments (`prime env`) | [environments.md](references/environments.md) |\n| Hosted Evaluations | Run evals on Prime-managed infra (`prime eval run --hosted`) | [environments.md](references/environments.md) |\n| Hosted Training | Post-train models against environments (`prime train`, Lab) | [environments.md](references/environments.md) |\n| prime-rl | Large-scale async RL framework for self-managed training | [environments.md](references/environments.md) |\n| Sandboxes | Secure disposable VM sandboxes for AI-generated code | [sandboxes.md](references/sandboxes.md) |\n| Tunnels | Public HTTPS URLs for local/sandboxed services | [sandboxes.md](references/sandboxes.md) |\n| Inference | OpenAI-compatible API for frontier models | [inference.md](references/inference.md) |\n| Compute | Rent single GPU pods or multi-node clusters | [compute.md](references/compute.md) |\n| Storage | Persistent disks shared between instances | [compute.md](references/compute.md) |\n\n## Prime CLI Setup\n\nDefault to the `prime` CLI for all Prime Intellect operations. If it is not installed:\n\n```bash\nuv tool install prime    # or: pip install prime\nprime login              # browser auth; or: prime config set-api-key\nprime config view        # verify configuration\n```\n\nThe same package provides the Python SDKs (e.g. `prime_sandboxes`, `prime_tunnel`). Source: https://github.com/PrimeIntellect-ai/prime\n\n## Live Documentation\n\nAuthoritative, current docs live at https://docs.primeintellect.ai. Any docs page is fetchable as Markdown by appending `.md` to its URL, and the full index is at https://docs.primeintellect.ai/llms.txt. When you need details not covered here (exact flags, API schemas, pricing, new features), fetch the live docs instead of guessing:\n\n```bash\ncurl -s https://docs.primeintellect.ai/llms.txt                      # discover pages\ncurl -s https://docs.primeintellect.ai/sandboxes/overview.md         # fetch a page as markdown\n```\n\nThe REST API is documented under `api-reference/` pages (OpenAPI spec: https://api.primeintellect.ai/openapi.json), with `https://api.primeintellect.ai` as the base URL.\n\n## Command Quick Reference\n\n```bash\n# Environments Hub\nprime env list --search \"math\"      # discover environments\nprime env info owner/name           # inspect one\nprime env install owner/name        # install locally\nprime env init my-env --v1          # scaffold a new environment\nprime env push                      # publish to the Hub\n\n# Evaluations\nprime eval run my-env -m openai/gpt-4.1-mini -n 5    # local smoke eval\nprime eval run owner/env --hosted --follow           # hosted eval with logs\n\n# Training\nprime lab setup                     # set up a Lab workspace (Hosted Training)\nprime train models                  # models, capacity, pricing\nprime train init && prime train rl.toml              # configure + launch a run\n\n# Sandboxes\nprime sandbox create python:3.11-slim --timeout-minutes 120\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox delete <sandbox-id>\n\n# Inference\nprime inference models              # list available models\n\n# Compute\nprime availability list             # GPU availability + pricing\nprime pods create                   # provision a pod\nprime pods ssh <pod-id>             # SSH in (needs: prime config set-ssh-key-path)\n```\n\n## Working Conventions\n\n- Prefer ecosystem-native paths (`prime env init`, `prime eval run`, `prime lab setup`) over custom scaffolding.\n- Smoke-test small (`-n 5`) before scaling evals or training; keep default result uploads unless the user explicitly opts out.\n- For non-trivial eval/training work, ask whether the user wants instruct models (`gpt-4.1` series, `qwen3` instruct) or reasoning models (`gpt-5` series, `qwen3` thinking, `glm` series).\n- Hosted Training launches from a CPU machine; self-managed `prime-rl` requires local GPU access and is a power-user path.\n- The dashboard at https://app.primeintellect.ai covers API keys, billing, teams, and anything the CLI does not.\n","frontmatter":{"name":"prime-intellect","description":"Work with Prime Intellect products via the prime CLI and Python SDKs - verifiers environments and the Environments Hub, evaluations (local and hosted), Hosted Training and prime-rl, code sandboxes, Prime Inference, GPU compute (pods and clusters), storage, and tunnels. Use when a task involves Prime Intellect, the prime CLI, verifiers, RL environments, evals, training, sandboxes, renting GPUs, Prime Inference models, or when the user asks what Prime Intellect is or what it offers."},"isInternal":false,"tokens":1178,"sizeBytes":5117},{"name":"SKILL.md","path":"skills/refine/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/refine/SKILL.md","title":"refine","category":"anthropic-skill","format":"markdown","content":"---\nname: refine\ndescription: Trigger continual harness refinement from the Python REPL. Use when you notice a repeated failure, reusable tactic, delegation role, or behavior policy that should be persisted as a harness entry. Returns immediately; refinement runs when the current turn ends.\n---\n\n# Refine\n\nRefinement analyzes the conversation trajectory and applies small, evidence-backed\nupdates to the continual harness (prompts, memories, skills, subagent specs).\nThe implementation lives in the host (the same one behind the user's `/refine`\ncommand); this skill is the kernel-side interface to it. Call it directly from\nthe Python REPL:\n\n```python\nawait refine.status()\nawait refine.run()\nawait refine.run(\"create a memory about always checking git status before committing\")\nawait refine.run(\"promote the error-handling pattern to a global skill\", global_=True)\n```\n\n## API\n\n- `await refine.status()` — current refine state as a dict: `pending` (whether a\n  requested refine is already queued for this turn) and `in_flight` (whether a\n  refine is currently planning or applying).\n- `await refine.run(instructions=None, global_=False)` — schedule refinement.\n  Returns `{\"scheduled\": True}` immediately, or `{\"scheduled\": False, \"reason\": ...}`\n  when refinement cannot start. Optional `instructions` focus the refinement on a\n  specific observation. Set `global_=True` to target the global harness store\n  (cross-session); omit for local (session-scoped) refinement.\n\n## Rules\n\n- Refinement never runs mid-cell. A scheduled refinement runs when the current\n  turn ends; the harness applies changes and rebuilds the system prompt, then\n  resumes you automatically. Continue working normally after calling it.\n- One request per turn is enough; calling `run` again before the turn ends only\n  updates the instructions.\n- Use refinement after observing a repeated failure, a reusable tactic, a\n  repeated delegation role, or a behavior policy worth persisting. Do not\n  rewrite the whole harness when a focused memory, skill, prompt note, or\n  subagent spec is enough.\n","frontmatter":{"name":"refine","description":"Trigger continual harness refinement from the Python REPL. Use when you notice a repeated failure, reusable tactic, delegation role, or behavior policy that should be persisted as a harness entry. Returns immediately; refinement runs when the current turn ends."},"isInternal":false,"tokens":440,"sizeBytes":2076},{"name":"SKILL.md","path":"skills/rlm-heartbeat/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/rlm-heartbeat/SKILL.md","title":"rlm-heartbeat","category":"anthropic-skill","format":"markdown","content":"---\nname: rlm-heartbeat\ndescription: Manage agent-owned RLM heartbeats from the Python REPL. Use when the user asks the agent to start, create, schedule, or manage a heartbeat, unless they explicitly request the user's /heartbeat.\n---\n\n# RLM Heartbeat\n\nRLM heartbeats are internal recurring prompts for the current agent session.\nThey are separate from the user's visible `/heartbeat`: this skill cannot read,\nreplace, pause, resume, or clear that user-level heartbeat.\n\nCall directly from the Python REPL:\n\n```python\nawait rlm_heartbeat.create(\"check test progress\", interval=\"5m\", label=\"tests\")\nawait rlm_heartbeat.create(\"watch build\", delivery_mode=\"follow_up\")\nawait rlm_heartbeat.list()\nawait rlm_heartbeat.update(\"job-id\", status=\"pause\")\nawait rlm_heartbeat.delete(\"job-id\")\n```\n\n## API\n\n- `await rlm_heartbeat.list(include_inactive=False)` — list this session's\n  internal RLM heartbeats. By default this includes active and paused entries.\n- `await rlm_heartbeat.create(instruction, interval=None, label=None,\n  delivery_mode=None)` — create a recurring heartbeat for this session. The\n  default interval is every 5 minutes. Multiple RLM heartbeats may run at once;\n  use labels to distinguish them. `delivery_mode` is `\"steer\"` (default) or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.update(id, instruction=None, interval=None, label=None,\n  status=None, delivery_mode=None)` — update one RLM heartbeat by id. `status`\n  may be `\"pause\"` or `\"resume\"`; `delivery_mode` may be `\"steer\"` or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.delete(id)` — cancel one RLM heartbeat by id.\n\n## Delivery mode\n\nEach heartbeat has a delivery mode controlling how the scheduled prompt reaches\nthe session when it is busy:\n\n- `steer` (default): interrupt the current turn so the heartbeat runs promptly.\n- `follow_up`: wait for the current turn to finish before running the heartbeat.\n\n## Rules\n\n- Use this when the user asks you to start, create, schedule, or manage your own\n  heartbeat without explicitly referring to `/heartbeat`.\n- Use this only for agent-internal recurring checks and long-running task\n  coordination.\n- Do not use this skill to satisfy a user's request to configure `/heartbeat`;\n  that is a separate user-level surface.\n- Keep heartbeat instructions specific and actionable so each recurring turn\n  knows exactly what to inspect or continue.\n","frontmatter":{"name":"rlm-heartbeat","description":"Manage agent-owned RLM heartbeats from the Python REPL. Use when the user asks the agent to start, create, schedule, or manage a heartbeat, unless they explicitly request the user's /heartbeat."},"isInternal":false,"tokens":542,"sizeBytes":2364},{"name":"python-skills.md","path":"skills/skill-creator/references/python-skills.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/skill-creator/references/python-skills.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Python-Backed Skills\n\nA Python-backed skill is a regular markdown skill that also ships a Python package. Prime Agent installs the package editable into the kernel venv (`~/.prime/agent/kernel-venv` by default, `PRIME_AGENT_KERNEL_VENV` to override) and exposes it in the persistent Python kernel, so the agent can call it directly instead of shelling out.\n\n## Detection Contract\n\nAll of these must hold or the skill silently degrades to a markdown-only skill (with a load warning):\n\n- `SKILL.md` exists as usual.\n- `pyproject.toml` exists at the skill root — its presence is what marks the skill as Python-backed.\n- The import name is the skill name with hyphens converted to underscores, and it must be a valid Python identifier.\n- `src/<import_name>/__init__.py` exists (src layout, exact directory name).\n\nFor a skill named `word-count`, the kernel exposes `word_count`.\n\n## Minimal Template\n\n```\nword-count/\n├── SKILL.md\n├── pyproject.toml\n└── src/\n    └── word_count/\n        └── __init__.py\n```\n\n**`SKILL.md`**\n\n```markdown\n---\nname: word-count\ndescription: Count word frequencies in text and return the most common words. Use when the user asks for word counts or frequency analysis of a text snippet.\n---\n\n# Word Count\n\nCall directly from the kernel:\n\n    await word_count(\"some text to analyze\", top=3)\n\nOr from a shell cell:\n\n    !word_count \"some text to analyze\" --top 3\n```\n\n**`pyproject.toml`**\n\n```toml\n[project]\nname = \"word-count\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = []\n\n[project.scripts]\nword_count = \"rlm.skill:cli\"\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/word_count\"]\n```\n\n**`src/word_count/__init__.py`**\n\n```python\nfrom collections import Counter\n\n\nasync def run(text: str, top: int = 5) -> str:\n    \"\"\"Count words in text and return the most common ones.\"\"\"\n    counts = Counter(text.lower().split())\n    return \"\\n\".join(f\"{word}: {count}\" for word, count in counts.most_common(top))\n```\n\nThe `[tool.hatch.build.targets.wheel]` section is required with hatchling whenever the project name differs from the package directory name (it always does for hyphenated skill names).\n\n## The run() Convention\n\nIf `src/<import_name>/__init__.py` defines `run()`, the kernel wraps the module so the module itself is an async callable:\n\n```python\nawait word_count(\"text\")        # same as word_count.run(\"text\")\nawait word_count.run(\"text\")\nhelp(word_count)                # shows run()'s docstring and signature\n```\n\n- `run()` may be sync or async; the wrapper awaits awaitable results.\n- The signature and docstring of `run()` are copied onto the module, so write a real docstring and typed keyword arguments with defaults — they are the skill's API documentation *and* its CLI.\n- Without `run()`, the module is still imported and exposed by name, just not callable.\n- Import failures do not break the kernel: the name is bound to a placeholder that raises a `RuntimeError` containing the import error when called.\n\n## Optional CLI Command\n\nThe `[project.scripts]` entry pointing at `rlm.skill:cli` gives the skill a shell command. Rules:\n\n- The script name must **exactly** match the Python import name, underscores included (`word_count`, not `word-count`).\n- `rlm.skill:cli` imports `<script_name>.run` and parses argv against its signature with `tyro`, awaits async results, and prints non-`None` return values.\n- `rlm` and `tyro` are already present in the kernel venv. Do **not** declare `prime-agent-runtime` as a dependency: it is bundled with Prime Agent, not published on PyPI, so declaring it breaks installs outside the kernel venv. The CLI entry point only works where the runtime is installed, i.e. inside the kernel venv.\n\nThe agent can then use either form:\n\n```python\nawait word_count(\"prime agent\", top=3)\n```\n\n```bash\n!word_count \"prime agent\" --top 3\n```\n\nOmit `[project.scripts]` when a CLI is not needed.\n\n## Dependencies and the Kernel Venv\n\n- Declare every third-party package `run()` imports in `dependencies` — `pyproject.toml` is the source of truth. The one exception is `prime-agent-runtime` (see above).\n- These are already in the kernel venv, so depending on them is free: `requests`, `httpx`, `pyyaml`, `tomli`, `python-dotenv`, `pandas`, `numpy`, `scipy`, `beautifulsoup4`, `lxml`, `pydantic`, `tyro`.\n- The install is editable and keyed on a hash of `pyproject.toml`: editing Python source takes effect on the next kernel start with no reinstall; editing `pyproject.toml` triggers a reinstall automatically.\n- If the user sets `PRIME_AGENT_KERNEL_PYTHON`, Prime Agent installs nothing — skills whose imports are missing there are disabled with a warning.\n\nA Python skill runs inside the agent's kernel, so it can itself spawn recursive sub-agents with `import rlm` and `await rlm.spawn(\"subtask\", name=\"worker\")` — useful for skills that delegate open-ended work.\n\n## Verifying a Python Skill\n\n1. Check the contract: skill name maps to a valid identifier, `src/<import_name>/__init__.py` exists, hatchling wheel packages list matches.\n2. Test `run()` standalone from the skill directory, without the kernel:\n\n   ```bash\n   cd <skill-dir> && uv run python -c \"import asyncio, word_count; print(asyncio.run(word_count.run('a b a', top=1)))\"\n   ```\n\n3. In a fresh agent session (the kernel installs skills at startup), confirm `help(<import_name>)` shows the docstring and `await <import_name>(...)` works. If it raises `RuntimeError`, the message contains the underlying import error.\n","isInternal":false,"tokens":1373,"sizeBytes":5583},{"name":"SKILL.md","path":"skills/skill-creator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/skill-creator/SKILL.md","title":"skill-creator","category":"anthropic-skill","format":"markdown","content":"---\nname: skill-creator\ndescription: Create, validate, and install Prime Agent skills - both markdown skills and Python-backed skills callable from the Python kernel. Use when the user asks to create a skill, turn a workflow, script, or prompt into a reusable skill, add a Python skill the agent can call, or asks how to write a SKILL.md and where skills live.\n---\n\n# Skill Creator\n\nA skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup Prime Agent reads only each skill's name and description into the system prompt; the full file loads on demand when a task matches. Prime Agent follows the [Agent Skills standard](https://agentskills.io/specification) and extends it with Python-backed skills.\n\n| Kind | What it is | When to use |\n|---|---|---|\n| markdown | `SKILL.md` plus optional scripts, references, and assets | Workflows, CLI recipes, domain knowledge, multi-step instructions |\n| python | A markdown skill that also ships a Python package installed into the agent's persistent Python kernel | Capabilities that are naturally one Python call: API wrappers, fetchers, converters, computations |\n\nBefore writing a Python-backed skill, read [references/python-skills.md](references/python-skills.md) for the package contract.\n\n## Creating a Skill\n\n1. **Pick the kind.** Default to markdown. Go Python only when the agent should *call* the capability (`await my_skill(...)`) instead of following instructions.\n2. **Pick the location.** Ask the user when it is not obvious from context:\n   - Project skill, shared via the repo: `.prime/agent/skills/<name>/`\n   - Personal global skill: `~/.prime/agent/skills/<name>/`\n   - Shipped with an npm package: a `skills/` directory in the package, or `pi.skills` paths in its `package.json`\n3. **Scaffold and write** the directory using the layout and frontmatter rules below.\n4. **Verify** the skill loads (see Verification).\n\nOn a name collision the first skill found wins. Precedence: explicit `--skill` paths and `skills` settings entries, then project, then global, then package, then built-in skills.\n\n## Layout\n\n```\nmy-skill/\n├── SKILL.md              # Required: frontmatter + instructions\n├── scripts/              # Optional helper scripts the instructions reference\n├── references/           # Optional detailed docs, loaded only when needed\n└── assets/               # Optional templates and data files\n```\n\nEverything except `SKILL.md` is freeform. Reference files with paths relative to the skill directory; the agent resolves them against the directory containing `SKILL.md`.\n\n## Frontmatter\n\n```markdown\n---\nname: my-skill\ndescription: What this skill does and when to use it. Be specific.\n---\n```\n\n| Field | Required | Rules |\n|---|---|---|\n| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. No leading/trailing/consecutive hyphens. Must match the parent directory name. |\n| `description` | Yes | Max 1024 chars. A skill with a missing or empty description is **silently not loaded**. |\n| `disable-model-invocation` | No | `true` hides the skill from the system prompt; only explicit `/skill:<name>` invokes it. |\n| `license` | No | License name or reference to a bundled file. |\n| `compatibility` | No | Max 500 chars. Environment requirements. |\n| `metadata` | No | Arbitrary key-value mapping. |\n| `allowed-tools` | No | Space-delimited pre-approved tools (experimental). |\n\nUnknown fields are ignored. Name violations produce warnings but the skill still loads.\n\n### Write the description for routing\n\nThe description is the only thing the model sees before deciding to load the skill. State what the skill does *and* the trigger conditions (\"Use when ...\"), naming the concrete tasks, tools, and phrases a request would contain.\n\nGood: `Extracts text and tables from PDF files, fills PDF forms, and merges PDFs. Use when working with PDF documents.`\nPoor: `Helps with PDFs.`\n\n### Write the body for progressive disclosure\n\nKeep `SKILL.md` short: the decision flow, the common commands, the contract. Push exhaustive detail (API schemas, full option lists, long examples) into `references/*.md` and link them, so they only enter context when actually needed. State setup steps (installs, env vars, credentials) explicitly and early.\n\n## Verification\n\nAfter writing the skill:\n\n1. Re-read the frontmatter and check every rule in the table above, especially that `name` matches the directory name and the description is non-empty.\n2. In an interactive session, `/reload` picks up new skills without a restart; other sessions pick them up on start. Loading problems (bad name, missing description, name collisions) surface as warnings — ask the user to check, or check diagnostics yourself if you can.\n3. A loaded skill is also invocable as `/skill:<name>`, which the user can try directly.\n\nFor Python-backed skills, also run the checks in [references/python-skills.md](references/python-skills.md).\n","frontmatter":{"name":"skill-creator","description":"Create, validate, and install Prime Agent skills - both markdown skills and Python-backed skills callable from the Python kernel. Use when the user asks to create a skill, turn a workflow, script, or prompt into a reusable skill, add a Python skill the agent can call, or asks how to write a SKILL.md and where skills live."},"isInternal":false,"tokens":1118,"sizeBytes":4947},{"name":"SKILL.md","path":"skills/websearch/SKILL.md","rawUrl":"https://raw.githubusercontent.com/PrimeIntellect-ai/prime-agent/HEAD/skills/websearch/SKILL.md","title":"websearch","category":"anthropic-skill","format":"markdown","content":"---\nname: websearch\ndescription: Search Google via the Serper API. Configure access via /mcp, then Serper (web search). Takes one query and returns titles, URLs, snippets, and knowledge-graph data.\n---\n\n# Web Search\n\nSearch the web via the Serper Google Search API.\n\n## Setup\n\nGet a free API key at https://serper.dev, then run `/mcp` in Prime Agent and\nchoose **Serper (web search)** to paste it.\nThe key is stored in Prime Agent and made available to this skill automatically.\n\nIf web search reports a missing key, walk the user through those two steps;\ndon't ask them to set environment variables.\n\nOptional overrides (environment variables):\n\n- `PRIME_AGENT_WEBSEARCH_TIMEOUT` - HTTP timeout in seconds (default 45).\n- `PRIME_AGENT_WEBSEARCH_NUM_RESULTS` - number of organic results to return (default 5).\n\n## Usage\n\nCall the prepared `websearch` import directly in the Python kernel:\n\n```python\nprint(await websearch(\"latest Prime Agent release\"))\n```\n","frontmatter":{"name":"websearch","description":"Search Google via the Serper API. Configure access via /mcp, then Serper (web search). Takes one query and returns titles, URLs, snippets, and knowledge-graph data."},"isInternal":false,"tokens":219,"sizeBytes":957}],"systemPromptSnippet":"<yakaai_skills repo=\"PrimeIntellect-ai/prime-agent\">\n<!-- File: AGENTS.md (Tokens: ~3373 | Category: root-instruction) -->\n# AGENTS.md\n\nDevelopment rules for Prime Agent (Rust) on PrimeIntellect-ai/prime-agent, branch `main`.\nEvery contributor (human or agent) must read this before working on this repo.\n\n## Repository\n\n- **Never set git identity for commits to this repo's history.** Agents must not set\n  `user.name`/`user.email` (config or `-c`) or `GIT_AUTHOR_NAME`/`GIT_AUTHOR_EMAIL`/\n  `GIT_COMMITTER_NAME`/`GIT_COMMITTER_EMAIL` for commits that land in this repository.\n  Those commits carry the identity of the ambient git config. If such a commit fails for a\n  missing identity, report it instead of adding config. Allowed: the `*_DATE` variables\n  (the golden corpus pins them for reproducibility), throwaway temp repos created by\n  tests, and the release automation's bot identity.\n- **Never add `Co-authored-by` trailers** — not in commit messages, not in squash\n  suggestions, not as attribution for work merged from branches. A PR's commits carry\n  one identity: the ambient git config's. Fabricated or hand-written trailers (including\n  noreply forms) misattribute commits to unrelated GitHub accounts.\n- The repo is PrimeIntellect-ai/prime-agent; the Rust implementation lives on the `main` branch.\n- PRs go to the org repo with base `main`:\n  `gh pr create --repo PrimeIntellect-ai/prime-agent --base main`.\n- CI runs on the org's billing: `.github/workflows/continuous.yml` on `main` pushes and\n  `release.yml` on version tags.\n- Parity ground truth is unchanged: a read-only checkout of the TS implementation (this\n  repo at tag `v0.9.8`, the last TS release before the Rust port merged to `main`). Clone\n  it to `~/prime-agent`, the conventional location the parity scripts and code fall back\n  to; tooling that honors an override reads `PA_TS_REFERENCE`.\n\n## Style and structure\n\n- Workspace crates are prefixed `pa-`. The hard ownership rules: one owned area per crate,\n  pa-types is the only shared crate, cycle-free dependency direction, minimal public APIs,\n  no god-modules. The dependency direction is pinned in the Crates table below; each crate's\n  README.md states its scope, non-goals, and public API surface.\n- Prefer private modules with an explicitly exported public crate API. Internals are `pub(crate)`.\n- Aim for files under 2,000 lines, tests included. The 2,000-2,100 range is a soft review\n  signal, not a merge limit: when adding to an already-large file, consider splitting by\n  responsibility rather than growing it further. Move related tests and docs with extracted code.\n- Name modules for what they own, not `utils` or `common`. Follow existing structure: in\n  `crates/pa-core/src/kernel/manager/`, `mod.rs` connects `execution.rs`, `requests.rs`, and\n  `teardown.rs`; put a new kernel-manager concern beside them. In\n  `crates/pa-core/src/cron/store/`, `mod.rs` connects `heartbeat.rs`, `jobs.rs`, and\n  `session_artifacts.rs`; keep storage work there rather than growing the scheduler.\n- Inline format args: always prefer `format!(\"{x}\")` over positional.\n- Collapse if statements per clippy::collapsible_if.\n- Prefer method references over closures per clippy::redundant_closure_for_method_calls.\n- Make `match` statements exhaustive; avoid wildcard arms.\n- New traits need doc comments explaining their role and how implementations are expected to behave.\n- No opaque positional `bool`/`Option` parameters (`foo(false)` is unreadable). Prefer enums,\n  named methods, or newtypes. If you must pass an opaque literal by position, use an exact\n  `/*param_name*/` comment matching the callee signature.\n- Prefer native RPITIT trait methods with explicit `Send` bounds\n  (`fn foo(&self) -> impl Future<Output = T> + Send;`) over `#[async_trait]` or\n  `#[allow(async_fn_in_trait)]`. Implementations may use `async fn` when they satisfy the contract.\n- No single-use helper methods. Do not create a helper referenced only once.\n- Instrument async work at the definition (`#[tracing::instrument(...)]`), not with\n  `.instrument(...)` at call sites. Check whether the callee is already instrumented first.\n\n## Change hygiene\n\n- One logical change per PR. Fixes ride with the change that introduced them when possible; a PR\n  that mixes a feature with unrelated lint fixes or refactors hides both from review.\n- If you change dependencies (`Cargo.toml`), regenerate/commit `Cargo.lock` in the same change.\n  A new dependency is an architectural change: state in the PR why the existing crates cannot\n  host the functionality, and `make deny` must stay clean for it.\n- If a change starts forcing edits across many crate internals, stop and fix the boundary instead.\n\n## Tests\n\n- Prefer whole-object equality comparisons over field-by-field checks.\n- Do not add tests for statically defined values.\n- Do not add negative tests for logic that was removed.\n- Bug fixes need a regression test that fails without the fix.\n- Verifiers over self-assessment: tmux user-level tests, differential tests against the TS binary\n  on PATH, golden corpora replayed against real captured data. No lane merges without its verifier\n  passing, rerun by the reviewer where feasible.\n- Tests must wait for observable readiness, not fixed sleeps or retry-to-green loops. If a\n  test must be disabled, give a reason at the test. Use isolated ports and temporary paths, and\n  restore shared state. Run focused tests when changing their behavior.\n\n## Lint discipline\n\n- Zero-warning posture: the merge gates run fmt + clippy + tests at `-D warnings`, so a `warn`\n  lint is a merge blocker. Keep the enabled set deliberate and selective; enable a new lint family\n  only with every current site fixed in the same change.\n- Explain lint exceptions next to the `#[allow(...)]` or workspace configuration; keep\n  exceptions narrow. Advisory ignores in `deny.toml` need a reason and review date.\n\n## Performance and the critical path\n\nThe UI critical path is paint-latency-critical. First paint, and every\nframe the user waits on, must never block on network, disk sync, or\nbackground bookkeeping. The launch benchmarks measure this surface\n(cold/warm ready, first paint); a merge that regresses them undoes the\nproduct's core claim.\n\nRules:\n\n- Nothing user-visible awaits the network. Any HTTP/socket call on a\n  render path (telemetry, catalog fetch, update check) runs on a\n  background worker; the paint path hands the work off and returns\n  immediately. Delivery semantics (timeout, retry, ordering) live with\n  the worker, not the caller.\n- Telemetry is fire-and-forget from user-facing code. `pa-telemetry`'s\n  background worker owns delivery end to end; no startup, session\n  create, tab open, or first-render path may hold a flush or await a\n  sink.\n- Fire-and-forget boundaries need a red-first test: a hanging sink\n  (one that never replies) must not delay paint. The test fails if any\n  await on the critical path reaches the worker's delivery.\n- Tests that mock a sink or run offline cannot prove the above (the\n  benchmark's mock hides the POST). The regression test with a hanging\n  sink is the required verifier.\n\nExample (the #3288 regression this rule exists to prevent): the\ntelemetry startup flush was awaited on the interactive launch path, so\nthe analytics POST — a real HTTPS round-trip, ~157 ms — ran before the\nfirst frame. Every CI check passed because tests set DO_NOT_TRACK=1 and\nthe benchmark mocked the provider offline; only real-network launches\npaid the cost. The fix moved the flush to the background worker and\nadded `the_startup_flush_never_blocks_the_first_frame` (a hanging sink\nmust not delay paint) as the permanent guard. Any change touching the\nlaunch path must keep that test red-first.\n\n\n## Merge gates\n\n- `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings`,\n  `cargo test --workspace` must pass before every merge. Run `make check` — the local mirror of\n  the same gates; CI runs on the org's billing (`.github/workflows/continuous.yml` on `main`\n  pushes; `release.yml` on version tags). The PR-only codebase-health check reports growth\n  past 2,000 lines as review guidance; it never blocks a merge.\n- **Parity-diff evidence is a merge gate** (the port's definition, not optional polish): every PR\n  that touches a user-visible surface must include a \"parity-diff evidence\" section in its\n  description showing the TS-binary comparison for what it changed: (1) rendered output —\n  frame-diff vs the TS binary;\n  (2) interactive behavior — the same input handled identically (keys, mouse, timing); \n  (3) wire parity — byte-compare the TS daemon's traffic for protocol changes; (4) user-visible\n  invariants — every user action produces the same visible reaction as TS (`/compact` shows\n  started+completed; `/model` shows the selector; a refinement shows its decoration). A feature\n  that \"works\" but was never diffed against the TS binary does not pass review. If TS shows it,\n  Rust shows it identically; if Rust shows something TS does not, that is also a parity bug.\n- PRs must state ownership compliance (crate README scope/non-goals/public API, dependency\n  direction) and classify the change: internals, new `pub` surface, or a new\n  dependency/cross-crate re-export. The latter two are architectural changes — an innocent-looking\n  `pub use` is a very simple way to break encapsulation.\n- The compiled fallback model catalog `crates/pa-ai/src/models_generated.rs` is\n  hand-maintained Rust mirroring the TS `packages/ai/src/models.generated.ts` object\n  literal — edit it by hand, exactly like its TS source (there is no generator). The\n  parity fixture `crates/pa-models/tests/fixtures/catalog.v1.json` refreshes with\n  `scripts/generate-catalog-fixture.py`. Bulk data files are exempt from the size guidance.\n\n## Adoption telemetry\n\nEvery user-visible feature ships its adoption telemetry event in the same PR as the feature:\nthe event name + properties join the versioned schema (`pa-telemetry`), and a\nseam emits it from day one. Telemetry properties never carry prompt, session, or file content\n(primitives only; see `pa-telemetry`); delivery is fire-and-forget from user-facing code\n(see Performance and the critical path).\n\n## Branding\n\nThe product is Prime Agent - we are not a pi fork. Scrub \"pi\"/\"pi-mono\"/\"pi-ai\"/\n\"Prime Intellect\"-style naming from all user-visible surfaces (docs, READMEs,\nCLI help text, error messages, splash/onboarding strings, keybinding hints, TUI\nlabels, and code comments that quote user-facing strings); brand everything\nPrime Agent. Audit with a repo-wide grep and classify every hit (user-visible\nvs wire-internal vs comment) before scrubbing, and list the preserved wire\nidentifiers in the PR body so the reviewer can verify none were wrongly scrubbed.\n\nEXPLICIT EXCEPTION: wire-protocol identifiers that must stay byte-compatible with the TS product (e.g. the PI_PACKAGE_DIR env var, settings keys, provider IDs like prime-inference, harness _meta namespaces like ai.primeintellect.prime-agent, lockfile names) stay until/unless the TS side renames them — PARITY BEATS BRANDING ON THE WIRE.\n\n\n\n## Surface contract (must not change)\n\n- Tools exposed to the model: `bash`, `edit`, `python_repl` (internal helpers: `rename`, `stdout`).\n- RLM kernel API in the persistent Python REPL: `rlm.spawn/find_models/collect/list_subagents/delete_subagent/create_session/progress_note`, `rlm.harness` CRUD, `agent_message.send`, `agent_observe`, `compact`, `goal`, `refine`, `attach_image`, skills (markdown + Python) per the skill contract in the base system prompt.\n- System prompt structure: layered — cache-stable static layer files (core harness description with the full API surface, mandatory usage rules, opinionated guidelines, per-model additions from the model-prompts TOML rule map) followed by one dynamic tail (packages, project context, skills inventory, MCP servers, environment, session role); the harness digest stays a separate `[harness-digest]` user message. `prime-agent prompt` dumps the assembled prompt with its layer breakdown.\n- CLI shape: `prime-agent` with the same commands/flags as the TS product; headless modes (RPC/daemon/session-worker) with identical behavior.\n\n## Crates\n\nOne owned area per crate; `pa-types` is the only shared vocabulary crate.\nDependencies flow from the composition root toward lower crates, never back upward.\nThe table summarizes each crate's current direct workspace dependencies:\n\n| Crate | Purpose | Direct workspace dependencies |\n| --- | --- | --- |\n| `pa-types` | Shared wire and domain types | none |\n| `pa-telemetry` | Events and sinks | none |\n| `pa-agent` | Provider-independent agent loop | none |\n| `pa-ai` | Providers, model registry, streaming | `pa-types` |\n| `pa-models` | Live model catalog and transport | `pa-ai`, `pa-types` |\n| `pa-core` | Session engine, tools, skills, kernel, settings | `pa-types`, `pa-ai`, `pa-models`, `pa-agent`, `pa-telemetry` |\n| `pa-daemon` | Supervisor, workers, wire protocol | `pa-types`, `pa-core`, `pa-agent`, `pa-ai`, `pa-telemetry`, `pa-models` |\n| `pa-tui` | Terminal UI, daemon-wire client | `pa-types` |\n| `pa-cli` | `prime-agent` binary, composition root | `pa-types`, `pa-core`, `pa-ai`, `pa-agent`, `pa-daemon`, `pa-tui`, `pa-telemetry` |\n| `pa-perf` | Performance corpora + pty bench harness (dev/CI tooling, never shipped) | `pa-types`, `pa-core`, `pa-daemon` |\n\nLayering rules:\n\n- Dependencies only point from higher crates to lower crates shown above. No cycles or\n  reverse edges. The leaf crates are peers; add only the dependencies needed for their work.\n  Shared wire/domain vocabulary belongs in `pa-types`, not in a higher crate or a duplicate.\n- `pa-tui` renders from wire types and events; it does not link the session engine.\n- `pa-cli` is a composition root: it wires crates together and contains no business logic.\n\n## Reliability model\n\n- The daemon is a supervisor: it spawns one worker process per active session instead of hosting sessions in-process. Workers are supervised, restarted with backoff, and sessions persist on disk (append-only JSONL, same layout as `~/.prime/agent/sessions`) so reattach works even if the supervisor restarts.\n- No stubs, no `todo!()`, no swallowed errors (`anyhow` bubbling to UI is fine).\n\n## References\n\n- Cursor Bugbot's PR review rules (`.cursor/BUGBOT.md`) mirror the standards in this file - update both whenever either changes.\n\n<!-- File: skills/agent-message/SKILL.md (Tokens: ~654 | Category: anthropic-skill) -->\n---\nname: agent-message\ndescription: Message an agent's parent, siblings, or direct children through the daemon. Discover reachable agents with agent_observe.list_agents, then send direct text without spoofing sender identity.\n---\n\n# Agent Message\n\nSend direct messages within the current agent's nuclear family through the\nlocal daemon: parent, siblings, and direct children only. Roots are siblings.\nThe daemon derives your sender identity from the current session; do not try\nto include a `from` field.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    receipt = await agent_message.send(\n        \"Please inspect the latest result.\",\n        receiver_role=\"child\",\n        receiver_name=child.session_name,\n    )\n    # Keep the child until this follow-up finishes so its result remains observable.\n```\n\n## API\n\n- `await agent_observe.list_agents()` (agent-observe skill) is the roster: it\n  lists the parent, siblings, and children this skill can reach, active or not,\n  with the `relationship` and `sessionName` that `send` takes as\n  `receiver_role` and `receiver_name`.\n- `await agent_message.send(message, receiver_role=\"parent\" | \"sibling\" | \"child\", receiver_name=None)` — sends one direct\n  text message to one family member. Sending to an inactive or idle completed\n  subagent wakes it and starts an ordinary follow-up turn in that same session\n  and context.\n  The child remains available only until its parent session closes. The daemon\n  resolves `receiver_role` within the current agent family; `receiver_name` is\n  required for siblings and children and omitted for the unique parent.\n  `send(\"all\", message)` broadcasts only to the family roster and returns\n  `{receipts: [...]}` in roster order; successful entries are ordinary receipts\n  and failed entries contain the target id and a short `error`. One failed delivery\n  does not reject successful deliveries. Messages always use steering delivery so\n  a busy target sees them during its active run. Returns a receipt with a\n  `deliveryStatus` field: `\"delivered\"` means the message reached an idle target's\n  context; `\"queued\"` means a steering message was accepted and will deliver when\n  the target's current work allows (`send` does not block waiting for that).\n  Delivered receipts carry `deliveredAt`, queued receipts carry `queuedAt`.\n\n## Safety\n\n- Do not delete a child immediately after `send`: delivered follow-ups may still\n  be running and queued receipts have not run yet. Wait until observation shows\n  the child is idle and its context is no longer needed before calling\n  `await rlm.delete_subagent(child)`.\n- Reach is limited to parent, siblings, and direct children; relay through an\n  intermediate child instead of messaging grandchildren or cousins directly.\n- Sender identity is daemon-derived and cannot be spoofed from Python.\n- The daemon enforces message size, rate, and pending-queue limits before\n  accepting delivery.\n\n<!-- File: skills/agent-observe/SKILL.md (Tokens: ~848 | Category: anthropic-skill) -->\n---\nname: agent-observe\ndescription: Read-only roster and observation of an agent's parent, siblings, and direct children. Use to discover reachable agents and to inspect family status and bounded recent-message previews without mutating sessions.\n---\n\n# Agent Observe\n\nObserve the current agent's nuclear family through the local daemon: parent,\nsiblings, direct children, and self. `list_agents` is the one family roster and\ncovers every member `agent_message.send` can reach. `get_agent` also returns an\ninactive child's roster row. `recent_messages` reads live sessions only; it\ndoes not rehydrate an inactive member. They cannot read a root sibling that has\nno live session in this worker.\nThis skill is read-only: it can list family sessions, inspect one session, and fetch\nbounded recent message previews. It cannot prompt, steer, clear, kill, rename, or\notherwise mutate another session.\n\nCall directly from the kernel:\n\n```python\nchildren = await rlm.list_subagents()\nchild = next((item for item in children if item.active_session_id), None)\nif child is not None:\n    worker = await agent_observe.get_agent(child.session_name)\n    recent = await agent_observe.recent_messages(child.session_name, limit=6)\n    # Deletion is a parent-owned RLM operation, not an observe mutation:\n    await rlm.delete_subagent(child)\n```\n\n## API\n\n- `await agent_observe.list_agents()` returns `current` (the calling agent's\n  own row) and `agents` (the family: parent, siblings, and direct children,\n  active or not; the caller is excluded from `agents`). Each row carries\n  `sessionId`, optional `sessionName`, `relationship`\n  (`parent`/`sibling`/`child`), `status` (`running`/`idle` for live sessions,\n  `inactive` without one), the live `activity` (`tool`/`model`/`compacting`/\n  `busy`/`user`/`idle`), `isSessionActive`, the counts known\n  for it (`messageCount`, `queuedCount`, `attachedClients`), `cwd` when the\n  roster row carries it, the parent edges (`parentActiveSessionId`,\n  `parentSessionId`) and `rlmChildId` for subagents, and `firstMessage`\n  (capped at 240 chars) for an inactive child. A member with no live session\n  has no `activeSessionId` and no live detail; address it with\n  `agent_message.send` using its `relationship` plus its `sessionName`, or its\n  `sessionId` when the member has no name. For direct children,\n  `await rlm.list_subagents()` also exposes parent-owned lifecycle handles.\n- `await agent_observe.get_agent(target)` returns `agent`, where `agent`\n  contains one agent summary (the same shape as the roster rows, including a\n  passive child's row). `target` is resolved like other live-session\n  selectors: active id, session id or name, or an unambiguous id suffix.\n- `await agent_observe.recent_messages(target, limit=8, max_chars=800)`\n  returns `agent` (the target's summary), `messages` (up to `limit` recent\n  bounded previews), the clamped `limit` and `maxChars`, and `truncated`\n  (true when older messages exist beyond the returned window). `limit` must be\n  1-50, and `max_chars` must be 80-2000. The target must be a live family\n  member: a member with no live session errors instead of hydrating.\n\n## Safety\n\n- This skill is read-only and exposes no mutation commands.\n- Targets outside the nuclear family are rejected; transcript reads follow the\n  same family rule as messaging.\n- Message access is bounded by count and per-message character limit.\n- Prefer status and recent previews for orchestration. Ask the user before\n  using observed context to steer or message another session.\n\n<!-- File: skills/attach-image/SKILL.md (Tokens: ~425 | Category: anthropic-skill) -->\n---\nname: attach-image\ndescription: Load an on-disk image (PNG, JPEG, GIF, WebP) into the model's context as a viewable attachment so the model can directly SEE it — for screenshots, diagrams, charts, photos, or scanned pages. Use this when you need to perceive an image's visual contents. Requires a vision-capable model; errors clearly otherwise.\n---\n\n# Attach Image\n\nLoad on-disk images into the model's context as multimodal attachments. The\nimage is sent to the model the same way a pasted image is, so the model can\nactually look at it.\n\n## When to use this\n\n- The user points at an image file and wants you to look at it.\n- You need to read text, a chart, a diagram, or a layout from an image.\n- A screenshot needs visual interpretation.\n\n## When NOT to use this\n\nFor *programmatic* work on an image — measuring pixels, cropping, resizing,\ncomputing a hash, comparing files byte-by-byte — open it in the kernel with a\nlibrary instead:\n\n```python\nfrom PIL import Image\nimg = Image.open(\"diagram.png\")\nprint(img.size)\n```\n\nThat path does not put the image in the model's context; it only lets you\ncompute over it. Use `attach_image` when you need to *see* the image.\n\n## Usage\n\nCall the prepared `attach_image` import directly in the Python kernel:\n\n```python\nprint(await attach_image(\"diagram.png\"))\nprint(await attach_image(\"a.png\", \"b.jpg\"))\n```\n\nThe skill automatically resizes and compresses large images before loading them\ninto context. Animated images that need compression are flattened to their first\nframe. Transparent images that need compression are composited onto a neutral\ngray background. Extremely large images are rejected by pixel count before full\nprocessing. The original file is left untouched.\n\nSupported formats: PNG, JPEG, GIF, WebP. The skill errors if a file is not a\nsupported image, or if the current model is not vision-capable.\n\n<!-- File: skills/compact/SKILL.md (Tokens: ~389 | Category: anthropic-skill) -->\n---\nname: compact\ndescription: Check context usage and compact the conversation from the Python REPL. Use when context is filling up and substantial work remains, so the session is summarized and you keep working instead of stopping early.\n---\n\n# Compact\n\nCompaction replaces older conversation history with a dense summary, freeing\ncontext so long-running work can continue. The implementation lives in the\nhost (the same one behind the user's `/compact` command); this skill is the\nkernel-side interface to it. Call it directly from the Python REPL:\n\n```python\nawait compact.status()\nawait compact.run()\nawait compact.run(\"keep the failing test names and the migration checklist\")\n```\n\n## API\n\n- `await compact.status()` — current context usage as a dict: `tokens`,\n  `context_window`, and `percent` (`None` right after a compaction until the\n  next model response), plus `scheduled` (whether a requested compaction is\n  already pending).\n- `await compact.run(instructions=None)` — schedule compaction. Returns\n  `{\"scheduled\": True}`, or `{\"scheduled\": False, \"reason\": ...}` when there\n  is nothing to compact yet. Optional `instructions` focus the summary on\n  what matters for the remaining work.\n\n## Rules\n\n- Compaction never runs mid-cell. A scheduled compaction runs when the\n  current turn ends; the harness then resumes you automatically with the\n  summary plus recent messages, and you continue the task.\n- The Python kernel persists through compaction — variables, imports, and\n  helpers you defined all remain available.\n- Compact at a natural boundary when context usage is high and substantial\n  work remains, instead of becoming terse or returning to the user early.\n  Check `await compact.status()` when unsure.\n- One request per turn is enough; calling `run` again before the turn ends\n  only updates the instructions.\n\n<!-- File: skills/edit/SKILL.md (Tokens: ~198 | Category: anthropic-skill) -->\n---\nname: edit\ndescription: Replace an exact, unique string in an existing file. Use for targeted single-occurrence edits to files from the Python kernel instead of rewriting the whole file.\n---\n\n# Edit\n\nMake a targeted edit to an existing file by replacing one exact, unique\noccurrence of a string. `old_str` must appear exactly once in the file.\n\nCall directly from the kernel:\n\n    await edit(path=\"pkg/file.py\", old_str=old, new_str=new)\n\nUse exact old/new strings. If the text contains triple double quotes, use\ntriple single-quoted variables (`old = '''...'''`) or build `old`/`new` from\ninspected file slices. Returns a short confirmation; raises if `old_str` is\nmissing or matches more than once (widen the snippet to make it unique).\n\nOr from a shell cell:\n\n    !edit --path pkg/file.py --old-str \"...\" --new-str \"...\"\n\n<!-- File: skills/factory/SKILL.md (Tokens: ~774 | Category: anthropic-skill) -->\n---\nname: factory\ndescription: Run state-machine workflows of spawned child agents: store a validated machine or dag spec as a continual-harness factory entry (rlm.harness.create_factory), then run, watch, stop, and resume it through rlm.factory. For the full authoring reference and API guide, call rlm.factory.help() in the kernel.\n---\n\n# Factory\n\nThe factory runs state-machine workflows of spawned child agents. A stored\nfactory entry — harness kind `factory`, written with\n`rlm.harness.create_factory` — declares the machine: states, each backed by\na subagent spec, plus guarded transitions between them. The spec validates\nat write time (machine form, or `dag` sugar that compiles to one; pass\nexactly one), and an invalid spec is never stored.\n`await rlm.factory.run('<spec_id>')` then spawns each state's subagent as an\nordinary child, feeds captured outputs into the successors' prompts, and\ndrives the run to quiescence in a background kernel task — the call\nreturns immediately and the run continues after the model turn ends. Use\nit when a workflow needs shape: fan-out, bounded loops (review/fix until a\nverdict approves), joins, or one child per list item.\n\n**For the full authoring reference and API guide — states, ports, guards,\njoins, foreach, residents, budgets and policies, and the `rlm.factory`\nrun/status/stop/resume/graph/watch calls with worked examples — call\n`rlm.factory.help()` in the kernel.** The guide lands with the factory-core\nPR; on builds without it, the module docstring in\n`prime-agent-runtime/src/rlm/factory.py` is the source of truth.\n\n## The opt-in gate\n\nThe factory ships disabled. `rlm.factory.help()` answers while it is off\n(the authoring guide stays readable before opting in), but every other\n`rlm.factory` call and every factory harness write refuses with one\nmessage: `the factory is disabled; run /factory on to enable it`. The\nuser turns it on with `/factory on` in the client (`/factory off`\ndisables it again — refused while the session still has live runs, and\non a lane-advertising client while the live-run count cannot be read, so\nan active factory never loses its stop path, `/factory status` reports\nit), which persists the\n`factory.enabled` setting in the agent dir's settings.json — the same\nsetting the daemon's `factory_activity` lane advertisement reads, so the\nTUI's factory dock group and page surface only on a client started while\nthe factory is enabled. If a call refuses with that message, tell the\nuser to run `/factory on` and restart the client.\n\n## Discovering machines\n\n- The machine library: machines are `MACHINE.md` files, one directory\n  per machine — the bundled seeds ship inside the runtime package (wheel\n  package data, `rlm/machines/<name>/MACHINE.md`; `PRIME_AGENT_MACHINES_DIR`\n  redirects that level at a team directory), and the personal library\n  lives under the agent dir. `prime-agent factory list | import | export`\n  manages them. The seeds are `builder`, `pr-manager`, and `review-sweep`.\n- The TUI factory page: the activity dock's `⚙ N factory` group (Enter or\n  click) opens one live diagram per run, newest run first. The up/down\n  arrows move the selection, Enter opens the selected run's action rows\n  (stop, or resume while it is paused — arrows to walk, Enter to run),\n  Esc closes.\n\n<!-- File: skills/goal/SKILL.md (Tokens: ~496 | Category: anthropic-skill) -->\n---\nname: goal\ndescription: Manage the persistent thread goal from the Python REPL. Use to read goal status and budget usage, to start a goal when the user explicitly asks for one, or to mark the active goal complete once its objective is fully achieved.\n---\n\n# Goal\n\nThe thread goal is a persistent objective the harness keeps re-prompting you to\npursue across turns until it is complete. Goal state (status, token budget,\nusage accounting) lives in the host; this skill is the kernel-side interface to\nit. Call it directly from the Python REPL:\n\n```python\nawait goal.get()\nawait goal.create(\"ship the release notes\")\n# Only pass token_budget when the user explicitly asks for one:\n# await goal.create(\"ship the release notes\", token_budget=200000)\nawait goal.complete()\n```\n\n## API\n\n- `await goal.get()` — current goal as a dict: `goal` (or `None` when no goal\n  is set), `remaining_tokens`, and `completion_budget_report`. The `goal` dict\n  carries `objective`, `status`, `token_budget`, `tokens_used`,\n  `time_used_seconds`, and timestamps.\n- `await goal.create(objective, token_budget=None)` — start a new active goal.\n  Fails while a goal is still pending (active, paused, or budget-limited); a\n  completed or errored goal is replaced by the new one. Only create a goal when\n  the user or system/developer instructions explicitly ask for a persistent\n  long-running goal; do not infer goals from ordinary tasks. Set `token_budget`\n  only when an explicit token budget is requested.\n- `await goal.complete()` — mark the existing goal achieved. Use only when the\n  objective has actually been achieved and no required work remains; do not\n  call it merely because the budget is nearly exhausted or because you are\n  stopping work. When the result includes a `completion_budget_report`, report\n  that final usage to the user.\n\n## Rules\n\n- Goal status transitions other than completion (pause, resume, clear,\n  budget-limiting) are controlled by the user and the host; there is no API for\n  them here.\n- When an active goal is actually complete, call `await goal.complete()`; do\n  not merely say it is done — the harness keeps continuing the goal until the\n  completion call arrives.\n\n<!-- File: skills/mcp/SKILL.md (Tokens: ~1010 | Category: anthropic-skill) -->\n---\nname: mcp\ndescription: Use external MCP services generically from Python - search the supported-service catalog, inspect the user's connections, discover live tool schemas, and call tools on any connection (Notion, Linear, Slack, and the rest of the catalog) without per-service packages.\n---\n\n# MCP Services\n\nEvery external service reachable over MCP uses the same pre-imported `mcp`\nmodule. Adding a service is data (a catalog entry plus a user login), never a\nnew Python package, and there are no per-service skills to read.\n\n## Inventory: what can I use?\n\n```python\n# Supported catalog, one bounded page. More pages exist while nextCursor is not None.\npage = await mcp.list_plugins(connection_status=\"not_connected\", limit=50)\nresults = await mcp.search_plugins(\"notion\")          # bounded search\npage = await mcp.list_plugins()                       # default: first 50 entries\n\n# The user's actual connections. connectionId is the dispatch id everywhere below.\nconnections = await mcp.list_connections()\n```\n\nCatalog entries carry `connectionStatus` (`connected`, `pending`,\n`not_connected`, `setup_required`, `disabled`, `error`), `connectable`, and\nwhen connected the `connectionIds` you dispatch on. `connected` means a\nverified MCP handshake, not just stored credentials; `pending` means\ncredentials exist but verification hasn't run or succeeded yet. Entries may\nalso carry `setupHint` (why a service isn't connectable yet), `unverified`\n(imported but not vetted), `verifiedAt`/`toolCount`, and `connectionIds`\n(empty when not dispatchable). Entries with `setup_required` need a developer\napp or API key first — say so honestly instead of promising one-click.\n\n## Recommend, never connect\n\nIf a task would benefit from an unconnected service, name the real catalog\nentry (e.g. \"Connecting Notion would let me search your workspace directly\")\nand tell the user to open `/plugins` (or run `/mcp login <service>`) to connect.\nRecommendations and catalog lookups never install anything, open a browser,\nuse credentials, or request extra scopes. There is no agent-initiated connect\ncall in this slice; if the user connects mid-task, the connection activates on\nthe next call without a reload.\n\n## Discover, then call\n\n```python\n# Live tool metadata is cached per connection; schemas come from the server.\ntools = await mcp.search_tools(\"search workspace documents\", connection_id=\"notion\")\ntool = await mcp.describe_tool(\"notion\", \"notion-search\")   # {name, description, inputSchema}\ntools = await mcp.list_tools(\"notion\")                     # full tool list with schemas\n\nresult = await mcp.call_tool(\"notion\", \"notion-search\", {\"query\": \"roadmap\"})\n```\n\n- Discover before calling: don't assume tool names or arguments; read the\n  `inputSchema` with `describe_tool` and construct matching arguments.\n- `list_tools` returns the complete inventory or raises — never a silent\n  partial list. Returned schemas are isolated copies; mutate them freely.\n- `search_tools` without a `connection_id` searches at most 8 connections the\n  host reports as connected and reports its scope: `searched`, `unavailable`\n  (per-connection failures as fixed, redaction-safe summaries), and\n  `truncated` (narrow the query or pick a connection when it is set — the\n  result never claims to be exhaustive).\n- Prefer narrow catalog searches over paging the whole catalog; don't dump all\n  schemas into context.\n- Results are already-parsed Python (a `dict` for structured output, otherwise\n  a string). No `json.loads` needed.\n\n## Errors and permissions\n\n- `PermissionError` — the tool is excluded by the user's `enabledTools` /\n  `disabledTools` policy. Don't retry; tell the user.\n- `KeyError` — the tool or connection doesn't exist. Re-check with\n  `list_tools` / `list_connections`; tools can change across sessions.\n- `McpDiscoveryError` — the server's tool listing couldn't complete honestly\n  (broken pagination). No partial inventory is published; re-run, and ask the\n  user to reconnect if it persists.\n- `RuntimeError` — credentials are not available (`McpCredentialsUnavailable`:\n  ask the user to connect via `/plugins` or `/mcp login <service>`, never via\n  environment variables), a refresh failed, or the host bridge is unavailable.\n- `McpToolError` — the server flagged the call as an error. Surface the\n  message; don't blindly retry a write that may have already happened.\n\nCredentials never appear in inventory results, tool schemas, or errors.\n\n<!-- File: skills/prime-intellect/references/compute.md (Tokens: ~430 | Category: anthropic-skill) -->\n# Compute & Storage\n\nPrime Intellect aggregates GPU capacity across providers: rent single GPU pods on demand or deploy multi-node clusters, with persistent network-attached storage.\n\nLive docs: `cli-reference/check-gpu-availability.md`, `cli-reference/provision-gpu.md`, `cli-reference/managing-disks.md`, `tutorials-multi-node-cluster/deploy-multi-node.md`, `tutorials-storage/create-persistent-storage.md` under https://docs.primeintellect.ai/\n\n## GPU Availability\n\n```bash\nprime availability list                        # all GPUs with pricing\nprime availability list --gpu-type H100_80GB   # filter by GPU type\n```\n\n## Pods (single instances)\n\n```bash\nprime config set-ssh-key-path   # one-time: SSH key for pod access (generate on the dashboard profile page)\nprime pods create               # interactive provisioning from availability data\nprime pods list\nprime pods ssh <pod-id>\n```\n\nPods support custom Docker images (`tutorials-on-demand-cloud/deploy-custom-docker-image.md`). Monitor, terminate, and inspect pods from the CLI or the dashboard.\n\n## Multi-Node Clusters\n\nDeploy multi-node clusters (with optional Slurm orchestration) from the platform; see `tutorials-multi-node-cluster/deploy-multi-node.md` and `tutorials-multi-node-cluster/slurm-orchestration.md`. Cluster monitoring guidance lives at `tutorials-reserved-clusters/monitoring.md`.\n\n## Storage\n\nPersistent disks outlive individual instances and can be attached to different instances as needed:\n\n- Create disks from the Storage tab of the Instances page (choose provider, datacenter, size), then attach them to pods or clusters.\n- Manage disks from the CLI as well — see `cli-reference/managing-disks.md`.\n- For multi-node shared and ephemeral storage patterns, see `tutorials-storage/cluster-storage.md`.\n\n## Teams\n\nManage team membership and run resources against team billing:\n\n```bash\nprime teams list\n```\n\nMost provisioning commands accept a `--team-id` flag; the REST API equivalent is the `X-Prime-Team-ID` header.\n\n<!-- File: skills/prime-intellect/references/environments.md (Tokens: ~1033 | Category: anthropic-skill) -->\n# Environments, Evaluations & Training\n\nverifiers is Prime Intellect's Python library for LLM environments: packages that expose `load_environment` and bundle datasets, rollout logic, and reward rubrics. Environments power evaluations (local and hosted) and RL training (Hosted Training or self-managed prime-rl).\n\nLive docs: `verifiers/overview.md`, `tutorials-environments/getting-started.md`, `hosted-training/getting-started.md`, `prime-rl/overview.md` under https://docs.primeintellect.ai/ (append `.md` for raw markdown). Source: https://github.com/PrimeIntellect-ai/verifiers and https://github.com/PrimeIntellect-ai/prime-rl\n\n## Discovering Environments (Hub)\n\n```bash\nprime env list --search \"math\" --owner primeintellect --show-actions\nprime env list --tag tools --tag sandbox\nprime env list --mine\nprime env list --starred\nprime env info owner/name        # metadata, version, dependencies\nprime env status owner/name      # CI/action status\nprime env pull owner/name -t ./tmp-env   # pull source for inspection\nprime env install owner/name     # install locally\n```\n\nWhen picking candidates, prefer: `primeintellect`-owned, passing latest actions, updated within ~2 months, recent verifiers versions. Compare task type (single-turn, multi-turn, tool, sandbox, agent), reward type (binary, continuous, judge-based), and dependency/secret requirements.\n\n## Creating Environments\n\n```bash\nprime env init my-env --v1       # scaffold (add --with-harness for an explicit reusable harness)\nprime env install my-env\nprime eval run my-env -m openai/gpt-4.1-mini -n 5   # smoke test immediately\nprime env push                   # publish to the Hub\n```\n\nBuild guidance:\n\n- Define the task contract first: prompt shape, allowed tools, stop conditions, rubric outputs, metrics.\n- Prefer starting from an existing Hub environment (`prime env list --search`, then `prime env install owner/name`) over building from scratch.\n- v1 environments expose `load_environment(config: vf.EnvConfig) -> vf.Env`; Taskset + Harness environments additionally expose `load_taskset(config)` and optionally `load_harness(config)` with `load_environment` delegating through `vf.load_taskset`/`vf.load_harness`.\n- The environment must install, load, evaluate, and train without hidden setup.\n\n## Evaluations\n\n`prime eval run` is the canonical eval path. Runs save automatically (visible in the Evaluations tab and `prime eval view`); do not add `--skip-upload` unless the user explicitly asks.\n\n```bash\nprime eval run my-env -m openai/gpt-4.1-mini -n 5               # smoke\nprime eval run owner/env -m openai/gpt-4.1-mini -n 200 -r 3 --shuffle -s   # scaled\nprime eval run owner/env --hosted --follow                       # hosted, streaming logs\n```\n\n- Smoke-test first; scale only after a pass. Use `--shuffle` (seed defaults to 0; set `--shuffle-seed` for reproducible reports).\n- Hosted evals require the environment to be published (`prime env push`) and support TOML configs and temporary sandbox/tunnel permissions (`--allow-tunnel-access`).\n- Prime Inference models include estimated run cost in eval output automatically.\n- Keep reusable model endpoints as aliases in `configs/endpoints.toml` (fields: `endpoint_id`, `model`, `url`, key) and reference them with `-m <endpoint_id>`.\n\n## Training\n\nDefault to Hosted Training unless the user explicitly wants self-managed infrastructure.\n\n```bash\nprime lab setup                  # Lab workspace for environments, evals, GEPA, Hosted Training\nprime train models               # supported models, capacity, pricing\nprime train init                 # generate a training config\nprime train rl.toml              # launch the run\n```\n\n- Hosted Training launches from a CPU machine; no local GPUs needed.\n- Validate the environment with an eval before training (e.g. `-n 20 -r 3 -s`) and confirm reward diversity exists at baseline.\n- Self-managed path: `prime lab setup --prime-rl`, then follow prime-rl's own configs and launch commands. Treat prime-rl as a power-user path requiring local GPU access; see https://docs.primeintellect.ai/prime-rl/overview.md.\n\n## Model Family Choice\n\nAsk the user whether they want instruct or reasoning models before non-trivial runs:\n\n- Instruct (quick behavior checks): `gpt-4.1` series, `qwen3` instruct series.\n- Reasoning (harder probes, deeper coverage): `gpt-5` series, `qwen3` thinking series, `glm` series.\n\n<!-- File: skills/prime-intellect/references/inference.md (Tokens: ~437 | Category: anthropic-skill) -->\n# Prime Inference\n\nPrime Inference is an OpenAI-compatible API for frontier and open models, routed across providers and built for large-scale evaluations.\n\nLive docs: `inference/overview.md`, `inference/usage.md`, `inference/adapter-deployments.md`, `inference/troubleshooting.md` under https://docs.primeintellect.ai/\n\n## Setup\n\n1. Create an API key on https://app.primeintellect.ai (account settings → API Keys) with the **Inference** permission enabled — without it, requests fail with authentication errors.\n2. Export it:\n\n```bash\nexport PRIME_API_KEY=\"your-api-key-here\"\n```\n\n## Via the CLI (recommended for evaluations)\n\n```bash\nprime inference models                                   # list available models\nprime eval run gsm8k -m meta-llama/llama-3.1-70b-instruct -n 25   # evals route through Prime Inference\n```\n\nEval runs against Prime Inference models report estimated USD cost automatically.\n\n## Direct API (OpenAI-compatible)\n\nBase URL: `https://api.pinference.ai/api/v1`\n\n```python\nimport openai, os\n\nclient = openai.OpenAI(\n    api_key=os.environ[\"PRIME_API_KEY\"],\n    base_url=\"https://api.pinference.ai/api/v1\",\n)\nresponse = client.chat.completions.create(\n    model=\"meta-llama/llama-3.1-70b-instruct\",\n    messages=[{\"role\": \"user\", \"content\": \"Hello!\"}],\n)\n```\n\nAnything that speaks the OpenAI API works — just point it at the base URL above. Streaming and advanced parameters are covered in `inference/usage.md`.\n\n## Teams & Adapters\n\n- Team billing: send the `X-Prime-Team-ID` header (find the ID via `prime teams list` or the Team Profile page) to use team credits instead of personal balance.\n- LoRA adapters trained with Hosted Training can be deployed and queried through the same OpenAI-compatible API (`inference/adapter-deployments.md`).\n\n<!-- File: skills/prime-intellect/references/sandboxes.md (Tokens: ~822 | Category: anthropic-skill) -->\n# Sandboxes & Tunnels\n\nPrime Sandboxes are disposable VM environments for running AI-generated or untrusted code in the cloud: isolated, fast to create, billed only while running (CPU $0.05/core/hr, memory $0.01/GB/hr, disk $0.001/GB/hr).\n\nLive docs: `sandboxes/overview.md`, `sandboxes/cli.md`, `sandboxes/sdk.md`, `sandboxes/images.md`, `sandboxes/tunnel.md` under https://docs.primeintellect.ai/\n\n## CLI Lifecycle\n\n```bash\nprime sandbox create python:3.11-slim --timeout-minutes 120   # any Docker image\nprime sandbox list\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox get <sandbox-id>\nprime sandbox delete <sandbox-id>\n```\n\nUseful create flags:\n\n```bash\nprime sandbox create python:3.11-slim \\\n  --name analytics-lab \\\n  --cpu-cores 2 --memory-gb 4 --disk-size-gb 20 \\\n  --timeout-minutes 240 \\\n  --idle-timeout-minutes 15 \\\n  --env APP_ENV=staging \\\n  --secret API_KEY=sk-abc123 \\\n  --yes\n```\n\n- `--timeout-minutes` caps total lifetime; `--idle-timeout-minutes` reaps the sandbox early when no exec/upload/download/file-read arrives (1 ≤ idle ≤ timeout ≤ 1440; for VM sandboxes, `timeout_minutes` may be negative to disable the lifetime deadline).\n- `--env` values are plain text; `--secret` values are encrypted at rest and obfuscated in output. Both become environment variables inside the sandbox.\n- Default start command keeps the sandbox idle, ready for `prime sandbox run`. To run your own process at boot, pass the command after `--` as separate tokens (no shell): `prime sandbox create python:3.11-slim -- python serve.py --port 8000`.\n- Outbound internet is on by default; restrict egress with network allow/deny lists (`prime sandbox network`, or `network_allowlist`/`network_denylist` in the SDK).\n- `--team-id` bills a team; `--yes` skips confirmation in automation.\n\nCustom images: build and push your own via Prime Images (`sandboxes/images.md`).\n\n## Python SDK\n\n`prime_sandboxes` ships `SandboxClient` (sync) and `AsyncSandboxClient` (async) with identical methods:\n\n```python\nfrom prime_sandboxes import SandboxClient, CreateSandboxRequest, APIClient\n\nclient = SandboxClient(APIClient())\nsandbox = client.create(CreateSandboxRequest(\n    name=\"sdk-demo\",\n    docker_image=\"python:3.11-slim\",\n    timeout_minutes=120,\n    environment_vars={\"LOG_LEVEL\": \"debug\"},\n    secrets={\"API_KEY\": \"sk-abc123\"},\n))\nclient.wait_for_creation(sandbox.id)\nresult = client.execute_command(sandbox.id, \"python -c 'print(42)'\")\nclient.upload_file(sandbox.id, \"/workspace/data.csv\", \"./data.csv\")\nclient.download_file(sandbox.id, \"/workspace/output.csv\", \"./output.csv\")\nclient.delete(sandbox.id)\n```\n\nAsync variant: `async with AsyncSandboxClient() as sandboxes: await sandboxes.create(...)` — same methods, useful for fanning out many sandboxes concurrently.\n\n## Tunnels\n\nPrime Tunnel exposes a local (or in-sandbox) service through a secure public HTTPS URL — for dev servers, webhooks, and sharing work in progress:\n\n```python\nfrom prime_tunnel import Tunnel\n\ntunnel = Tunnel(local_port=8000)\nawait tunnel.start()   # prints the public URL\n```\n\nHosted evaluations can create tunnels too: launch the run with `--allow-tunnel-access` (grants tunnel permission to the temporary `PRIME_API_KEY`), then use the same flow inside the hosted sandbox.\n\n<!-- File: skills/prime-intellect/SKILL.md (Tokens: ~1178 | Category: anthropic-skill) -->\n---\nname: prime-intellect\ndescription: Work with Prime Intellect products via the prime CLI and Python SDKs - verifiers environments and the Environments Hub, evaluations (local and hosted), Hosted Training and prime-rl, code sandboxes, Prime Inference, GPU compute (pods and clusters), storage, and tunnels. Use when a task involves Prime Intellect, the prime CLI, verifiers, RL environments, evals, training, sandboxes, renting GPUs, Prime Inference models, or when the user asks what Prime Intellect is or what it offers.\n---\n\n# Prime Intellect\n\nPrime Intellect is an open superintelligence lab building open-source AGI infrastructure: a platform for RL environments, evaluations, post-training, inference, and globally distributed GPU compute. Prime Agent (this agent) is built by Prime Intellect, and the `prime` CLI is the default way to interface with every product below.\n\n## Product Map\n\n| Product | What it is | Details |\n|---|---|---|\n| verifiers | Python library for building LLM environments and evaluations | [environments.md](references/environments.md) |\n| Environments Hub | Platform library of community RL environments (`prime env`) | [environments.md](references/environments.md) |\n| Hosted Evaluations | Run evals on Prime-managed infra (`prime eval run --hosted`) | [environments.md](references/environments.md) |\n| Hosted Training | Post-train models against environments (`prime train`, Lab) | [environments.md](references/environments.md) |\n| prime-rl | Large-scale async RL framework for self-managed training | [environments.md](references/environments.md) |\n| Sandboxes | Secure disposable VM sandboxes for AI-generated code | [sandboxes.md](references/sandboxes.md) |\n| Tunnels | Public HTTPS URLs for local/sandboxed services | [sandboxes.md](references/sandboxes.md) |\n| Inference | OpenAI-compatible API for frontier models | [inference.md](references/inference.md) |\n| Compute | Rent single GPU pods or multi-node clusters | [compute.md](references/compute.md) |\n| Storage | Persistent disks shared between instances | [compute.md](references/compute.md) |\n\n## Prime CLI Setup\n\nDefault to the `prime` CLI for all Prime Intellect operations. If it is not installed:\n\n```bash\nuv tool install prime    # or: pip install prime\nprime login              # browser auth; or: prime config set-api-key\nprime config view        # verify configuration\n```\n\nThe same package provides the Python SDKs (e.g. `prime_sandboxes`, `prime_tunnel`). Source: https://github.com/PrimeIntellect-ai/prime\n\n## Live Documentation\n\nAuthoritative, current docs live at https://docs.primeintellect.ai. Any docs page is fetchable as Markdown by appending `.md` to its URL, and the full index is at https://docs.primeintellect.ai/llms.txt. When you need details not covered here (exact flags, API schemas, pricing, new features), fetch the live docs instead of guessing:\n\n```bash\ncurl -s https://docs.primeintellect.ai/llms.txt                      # discover pages\ncurl -s https://docs.primeintellect.ai/sandboxes/overview.md         # fetch a page as markdown\n```\n\nThe REST API is documented under `api-reference/` pages (OpenAPI spec: https://api.primeintellect.ai/openapi.json), with `https://api.primeintellect.ai` as the base URL.\n\n## Command Quick Reference\n\n```bash\n# Environments Hub\nprime env list --search \"math\"      # discover environments\nprime env info owner/name           # inspect one\nprime env install owner/name        # install locally\nprime env init my-env --v1          # scaffold a new environment\nprime env push                      # publish to the Hub\n\n# Evaluations\nprime eval run my-env -m openai/gpt-4.1-mini -n 5    # local smoke eval\nprime eval run owner/env --hosted --follow           # hosted eval with logs\n\n# Training\nprime lab setup                     # set up a Lab workspace (Hosted Training)\nprime train models                  # models, capacity, pricing\nprime train init && prime train rl.toml              # configure + launch a run\n\n# Sandboxes\nprime sandbox create python:3.11-slim --timeout-minutes 120\nprime sandbox run <sandbox-id> \"python --version\"\nprime sandbox delete <sandbox-id>\n\n# Inference\nprime inference models              # list available models\n\n# Compute\nprime availability list             # GPU availability + pricing\nprime pods create                   # provision a pod\nprime pods ssh <pod-id>             # SSH in (needs: prime config set-ssh-key-path)\n```\n\n## Working Conventions\n\n- Prefer ecosystem-native paths (`prime env init`, `prime eval run`, `prime lab setup`) over custom scaffolding.\n- Smoke-test small (`-n 5`) before scaling evals or training; keep default result uploads unless the user explicitly opts out.\n- For non-trivial eval/training work, ask whether the user wants instruct models (`gpt-4.1` series, `qwen3` instruct) or reasoning models (`gpt-5` series, `qwen3` thinking, `glm` series).\n- Hosted Training launches from a CPU machine; self-managed `prime-rl` requires local GPU access and is a power-user path.\n- The dashboard at https://app.primeintellect.ai covers API keys, billing, teams, and anything the CLI does not.\n\n<!-- File: skills/refine/SKILL.md (Tokens: ~440 | Category: anthropic-skill) -->\n---\nname: refine\ndescription: Trigger continual harness refinement from the Python REPL. Use when you notice a repeated failure, reusable tactic, delegation role, or behavior policy that should be persisted as a harness entry. Returns immediately; refinement runs when the current turn ends.\n---\n\n# Refine\n\nRefinement analyzes the conversation trajectory and applies small, evidence-backed\nupdates to the continual harness (prompts, memories, skills, subagent specs).\nThe implementation lives in the host (the same one behind the user's `/refine`\ncommand); this skill is the kernel-side interface to it. Call it directly from\nthe Python REPL:\n\n```python\nawait refine.status()\nawait refine.run()\nawait refine.run(\"create a memory about always checking git status before committing\")\nawait refine.run(\"promote the error-handling pattern to a global skill\", global_=True)\n```\n\n## API\n\n- `await refine.status()` — current refine state as a dict: `pending` (whether a\n  requested refine is already queued for this turn) and `in_flight` (whether a\n  refine is currently planning or applying).\n- `await refine.run(instructions=None, global_=False)` — schedule refinement.\n  Returns `{\"scheduled\": True}` immediately, or `{\"scheduled\": False, \"reason\": ...}`\n  when refinement cannot start. Optional `instructions` focus the refinement on a\n  specific observation. Set `global_=True` to target the global harness store\n  (cross-session); omit for local (session-scoped) refinement.\n\n## Rules\n\n- Refinement never runs mid-cell. A scheduled refinement runs when the current\n  turn ends; the harness applies changes and rebuilds the system prompt, then\n  resumes you automatically. Continue working normally after calling it.\n- One request per turn is enough; calling `run` again before the turn ends only\n  updates the instructions.\n- Use refinement after observing a repeated failure, a reusable tactic, a\n  repeated delegation role, or a behavior policy worth persisting. Do not\n  rewrite the whole harness when a focused memory, skill, prompt note, or\n  subagent spec is enough.\n\n<!-- File: skills/rlm-heartbeat/SKILL.md (Tokens: ~542 | Category: anthropic-skill) -->\n---\nname: rlm-heartbeat\ndescription: Manage agent-owned RLM heartbeats from the Python REPL. Use when the user asks the agent to start, create, schedule, or manage a heartbeat, unless they explicitly request the user's /heartbeat.\n---\n\n# RLM Heartbeat\n\nRLM heartbeats are internal recurring prompts for the current agent session.\nThey are separate from the user's visible `/heartbeat`: this skill cannot read,\nreplace, pause, resume, or clear that user-level heartbeat.\n\nCall directly from the Python REPL:\n\n```python\nawait rlm_heartbeat.create(\"check test progress\", interval=\"5m\", label=\"tests\")\nawait rlm_heartbeat.create(\"watch build\", delivery_mode=\"follow_up\")\nawait rlm_heartbeat.list()\nawait rlm_heartbeat.update(\"job-id\", status=\"pause\")\nawait rlm_heartbeat.delete(\"job-id\")\n```\n\n## API\n\n- `await rlm_heartbeat.list(include_inactive=False)` — list this session's\n  internal RLM heartbeats. By default this includes active and paused entries.\n- `await rlm_heartbeat.create(instruction, interval=None, label=None,\n  delivery_mode=None)` — create a recurring heartbeat for this session. The\n  default interval is every 5 minutes. Multiple RLM heartbeats may run at once;\n  use labels to distinguish them. `delivery_mode` is `\"steer\"` (default) or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.update(id, instruction=None, interval=None, label=None,\n  status=None, delivery_mode=None)` — update one RLM heartbeat by id. `status`\n  may be `\"pause\"` or `\"resume\"`; `delivery_mode` may be `\"steer\"` or\n  `\"follow_up\"`.\n- `await rlm_heartbeat.delete(id)` — cancel one RLM heartbeat by id.\n\n## Delivery mode\n\nEach heartbeat has a delivery mode controlling how the scheduled prompt reaches\nthe session when it is busy:\n\n- `steer` (default): interrupt the current turn so the heartbeat runs promptly.\n- `follow_up`: wait for the current turn to finish before running the heartbeat.\n\n## Rules\n\n- Use this when the user asks you to start, create, schedule, or manage your own\n  heartbeat without explicitly referring to `/heartbeat`.\n- Use this only for agent-internal recurring checks and long-running task\n  coordination.\n- Do not use this skill to satisfy a user's request to configure `/heartbeat`;\n  that is a separate user-level surface.\n- Keep heartbeat instructions specific and actionable so each recurring turn\n  knows exactly what to inspect or continue.\n\n<!-- File: skills/skill-creator/references/python-skills.md (Tokens: ~1373 | Category: anthropic-skill) -->\n# Python-Backed Skills\n\nA Python-backed skill is a regular markdown skill that also ships a Python package. Prime Agent installs the package editable into the kernel venv (`~/.prime/agent/kernel-venv` by default, `PRIME_AGENT_KERNEL_VENV` to override) and exposes it in the persistent Python kernel, so the agent can call it directly instead of shelling out.\n\n## Detection Contract\n\nAll of these must hold or the skill silently degrades to a markdown-only skill (with a load warning):\n\n- `SKILL.md` exists as usual.\n- `pyproject.toml` exists at the skill root — its presence is what marks the skill as Python-backed.\n- The import name is the skill name with hyphens converted to underscores, and it must be a valid Python identifier.\n- `src/<import_name>/__init__.py` exists (src layout, exact directory name).\n\nFor a skill named `word-count`, the kernel exposes `word_count`.\n\n## Minimal Template\n\n```\nword-count/\n├── SKILL.md\n├── pyproject.toml\n└── src/\n    └── word_count/\n        └── __init__.py\n```\n\n**`SKILL.md`**\n\n```markdown\n---\nname: word-count\ndescription: Count word frequencies in text and return the most common words. Use when the user asks for word counts or frequency analysis of a text snippet.\n---\n\n# Word Count\n\nCall directly from the kernel:\n\n    await word_count(\"some text to analyze\", top=3)\n\nOr from a shell cell:\n\n    !word_count \"some text to analyze\" --top 3\n```\n\n**`pyproject.toml`**\n\n```toml\n[project]\nname = \"word-count\"\nversion = \"0.1.0\"\nrequires-python = \">=3.10\"\ndependencies = []\n\n[project.scripts]\nword_count = \"rlm.skill:cli\"\n\n[build-system]\nrequires = [\"hatchling\"]\nbuild-backend = \"hatchling.build\"\n\n[tool.hatch.build.targets.wheel]\npackages = [\"src/word_count\"]\n```\n\n**`src/word_count/__init__.py`**\n\n```python\nfrom collections import Counter\n\n\nasync def run(text: str, top: int = 5) -> str:\n    \"\"\"Count words in text and return the most common ones.\"\"\"\n    counts = Counter(text.lower().split())\n    return \"\\n\".join(f\"{word}: {count}\" for word, count in counts.most_common(top))\n```\n\nThe `[tool.hatch.build.targets.wheel]` section is required with hatchling whenever the project name differs from the package directory name (it always does for hyphenated skill names).\n\n## The run() Convention\n\nIf `src/<import_name>/__init__.py` defines `run()`, the kernel wraps the module so the module itself is an async callable:\n\n```python\nawait word_count(\"text\")        # same as word_count.run(\"text\")\nawait word_count.run(\"text\")\nhelp(word_count)                # shows run()'s docstring and signature\n```\n\n- `run()` may be sync or async; the wrapper awaits awaitable results.\n- The signature and docstring of `run()` are copied onto the module, so write a real docstring and typed keyword arguments with defaults — they are the skill's API documentation *and* its CLI.\n- Without `run()`, the module is still imported and exposed by name, just not callable.\n- Import failures do not break the kernel: the name is bound to a placeholder that raises a `RuntimeError` containing the import error when called.\n\n## Optional CLI Command\n\nThe `[project.scripts]` entry pointing at `rlm.skill:cli` gives the skill a shell command. Rules:\n\n- The script name must **exactly** match the Python import name, underscores included (`word_count`, not `word-count`).\n- `rlm.skill:cli` imports `<script_name>.run` and parses argv against its signature with `tyro`, awaits async results, and prints non-`None` return values.\n- `rlm` and `tyro` are already present in the kernel venv. Do **not** declare `prime-agent-runtime` as a dependency: it is bundled with Prime Agent, not published on PyPI, so declaring it breaks installs outside the kernel venv. The CLI entry point only works where the runtime is installed, i.e. inside the kernel venv.\n\nThe agent can then use either form:\n\n```python\nawait word_count(\"prime agent\", top=3)\n```\n\n```bash\n!word_count \"prime agent\" --top 3\n```\n\nOmit `[project.scripts]` when a CLI is not needed.\n\n## Dependencies and the Kernel Venv\n\n- Declare every third-party package `run()` imports in `dependencies` — `pyproject.toml` is the source of truth. The one exception is `prime-agent-runtime` (see above).\n- These are already in the kernel venv, so depending on them is free: `requests`, `httpx`, `pyyaml`, `tomli`, `python-dotenv`, `pandas`, `numpy`, `scipy`, `beautifulsoup4`, `lxml`, `pydantic`, `tyro`.\n- The install is editable and keyed on a hash of `pyproject.toml`: editing Python source takes effect on the next kernel start with no reinstall; editing `pyproject.toml` triggers a reinstall automatically.\n- If the user sets `PRIME_AGENT_KERNEL_PYTHON`, Prime Agent installs nothing — skills whose imports are missing there are disabled with a warning.\n\nA Python skill runs inside the agent's kernel, so it can itself spawn recursive sub-agents with `import rlm` and `await rlm.spawn(\"subtask\", name=\"worker\")` — useful for skills that delegate open-ended work.\n\n## Verifying a Python Skill\n\n1. Check the contract: skill name maps to a valid identifier, `src/<import_name>/__init__.py` exists, hatchling wheel packages list matches.\n2. Test `run()` standalone from the skill directory, without the kernel:\n\n   ```bash\n   cd <skill-dir> && uv run python -c \"import asyncio, word_count; print(asyncio.run(word_count.run('a b a', top=1)))\"\n   ```\n\n3. In a fresh agent session (the kernel installs skills at startup), confirm `help(<import_name>)` shows the docstring and `await <import_name>(...)` works. If it raises `RuntimeError`, the message contains the underlying import error.\n\n<!-- File: skills/skill-creator/SKILL.md (Tokens: ~1118 | Category: anthropic-skill) -->\n---\nname: skill-creator\ndescription: Create, validate, and install Prime Agent skills - both markdown skills and Python-backed skills callable from the Python kernel. Use when the user asks to create a skill, turn a workflow, script, or prompt into a reusable skill, add a Python skill the agent can call, or asks how to write a SKILL.md and where skills live.\n---\n\n# Skill Creator\n\nA skill is a directory with a `SKILL.md` file (YAML frontmatter + markdown instructions). At startup Prime Agent reads only each skill's name and description into the system prompt; the full file loads on demand when a task matches. Prime Agent follows the [Agent Skills standard](https://agentskills.io/specification) and extends it with Python-backed skills.\n\n| Kind | What it is | When to use |\n|---|---|---|\n| markdown | `SKILL.md` plus optional scripts, references, and assets | Workflows, CLI recipes, domain knowledge, multi-step instructions |\n| python | A markdown skill that also ships a Python package installed into the agent's persistent Python kernel | Capabilities that are naturally one Python call: API wrappers, fetchers, converters, computations |\n\nBefore writing a Python-backed skill, read [references/python-skills.md](references/python-skills.md) for the package contract.\n\n## Creating a Skill\n\n1. **Pick the kind.** Default to markdown. Go Python only when the agent should *call* the capability (`await my_skill(...)`) instead of following instructions.\n2. **Pick the location.** Ask the user when it is not obvious from context:\n   - Project skill, shared via the repo: `.prime/agent/skills/<name>/`\n   - Personal global skill: `~/.prime/agent/skills/<name>/`\n   - Shipped with an npm package: a `skills/` directory in the package, or `pi.skills` paths in its `package.json`\n3. **Scaffold and write** the directory using the layout and frontmatter rules below.\n4. **Verify** the skill loads (see Verification).\n\nOn a name collision the first skill found wins. Precedence: explicit `--skill` paths and `skills` settings entries, then project, then global, then package, then built-in skills.\n\n## Layout\n\n```\nmy-skill/\n├── SKILL.md              # Required: frontmatter + instructions\n├── scripts/              # Optional helper scripts the instructions reference\n├── references/           # Optional detailed docs, loaded only when needed\n└── assets/               # Optional templates and data files\n```\n\nEverything except `SKILL.md` is freeform. Reference files with paths relative to the skill directory; the agent resolves them against the directory containing `SKILL.md`.\n\n## Frontmatter\n\n```markdown\n---\nname: my-skill\ndescription: What this skill does and when to use it. Be specific.\n---\n```\n\n| Field | Required | Rules |\n|---|---|---|\n| `name` | Yes | Max 64 chars. Lowercase a-z, 0-9, hyphens. No leading/trailing/consecutive hyphens. Must match the parent directory name. |\n| `description` | Yes | Max 1024 chars. A skill with a missing or empty description is **silently not loaded**. |\n| `disable-model-invocation` | No | `true` hides the skill from the system prompt; only explicit `/skill:<name>` invokes it. |\n| `license` | No | License name or reference to a bundled file. |\n| `compatibility` | No | Max 500 chars. Environment requirements. |\n| `metadata` | No | Arbitrary key-value mapping. |\n| `allowed-tools` | No | Space-delimited pre-approved tools (experimental). |\n\nUnknown fields are ignored. Name violations produce warnings but the skill still loads.\n\n### Write the description for routing\n\nThe description is the only thing the model sees before deciding to load the skill. State what the skill does *and* the trigger conditions (\"Use when ...\"), naming the concrete tasks, tools, and phrases a request would contain.\n\nGood: `Extracts text and tables from PDF files, fills PDF forms, and merges PDFs. Use when working with PDF documents.`\nPoor: `Helps with PDFs.`\n\n### Write the body for progressive disclosure\n\nKeep `SKILL.md` short: the decision flow, the common commands, the contract. Push exhaustive detail (API schemas, full option lists, long examples) into `references/*.md` and link them, so they only enter context when actually needed. State setup steps (installs, env vars, credentials) explicitly and early.\n\n## Verification\n\nAfter writing the skill:\n\n1. Re-read the frontmatter and check every rule in the table above, especially that `name` matches the directory name and the description is non-empty.\n2. In an interactive session, `/reload` picks up new skills without a restart; other sessions pick them up on start. Loading problems (bad name, missing description, name collisions) surface as warnings — ask the user to check, or check diagnostics yourself if you can.\n3. A loaded skill is also invocable as `/skill:<name>`, which the user can try directly.\n\nFor Python-backed skills, also run the checks in [references/python-skills.md](references/python-skills.md).\n\n<!-- File: skills/websearch/SKILL.md (Tokens: ~219 | Category: anthropic-skill) -->\n---\nname: websearch\ndescription: Search Google via the Serper API. Configure access via /mcp, then Serper (web search). Takes one query and returns titles, URLs, snippets, and knowledge-graph data.\n---\n\n# Web Search\n\nSearch the web via the Serper Google Search API.\n\n## Setup\n\nGet a free API key at https://serper.dev, then run `/mcp` in Prime Agent and\nchoose **Serper (web search)** to paste it.\nThe key is stored in Prime Agent and made available to this skill automatically.\n\nIf web search reports a missing key, walk the user through those two steps;\ndon't ask them to set environment variables.\n\nOptional overrides (environment variables):\n\n- `PRIME_AGENT_WEBSEARCH_TIMEOUT` - HTTP timeout in seconds (default 45).\n- `PRIME_AGENT_WEBSEARCH_NUM_RESULTS` - number of organic results to return (default 5).\n\n## Usage\n\nCall the prepared `websearch` import directly in the Python kernel:\n\n```python\nprint(await websearch(\"latest Prime Agent release\"))\n```\n</yakaai_skills>"}