Skip to main content

Rail harness control plane with a Python Actor Runtime.

Project description

rail

rail is a skill-first harness control plane for bounded agentic software work.

The canonical product contract is docs/SPEC.md.

The product contract is:

  • users describe work in natural language through the Rail skill
  • the Rail skill creates a structured request draft
  • the Python Rail Harness Runtime normalizes that draft, allocates an artifact handle, supervises bounded actors, validates evidence, and projects the result

Users should not hand-write harness YAML or manage task ids.

Runtime Boundary

Rail owns the governance layer:

  • request normalization
  • artifact identity and resume policy
  • Actor Runtime policy
  • supervisor routing
  • sandbox and patch bundle mutation boundaries
  • validation evidence
  • evaluator gate decisions
  • result and status projection

The Actor Runtime is the SDK-powered execution boundary for bounded actor work. It receives a narrowed policy and schema-bound prompt, then returns structured actor output and evidence references. Target repository mutation happens only through Rail-validated patch bundles.

Python API

The primary product boundary is the Python API:

import rail

draft = {
    "project_root": "/absolute/path/to/target-repo",
    "task_type": "bug_fix",
    "goal": "Fix the intermittent profile refresh loading issue.",
    "constraints": ["Do not change the API contract."],
    "definition_of_done": ["Refresh completes reliably.", "Focused validation passes."],
}

handle = rail.start_task(draft)
rail.supervise(handle)
result = rail.result(handle)

The optional command surface, when present, is only a thin wrapper over this API.

Task Identity And Resume

start_task(draft) always allocates a fresh artifact for a fresh goal. This remains true even when an older artifact is blocked, rejected, or failed.

Existing artifact operations use the artifact handle returned by start_task. A request file path is not run identity, and users do not choose task ids.

Resume-like intents such as continue, retry, status, result, debug, or integrate require a known artifact handle. Without one, Rail asks for clarification instead of guessing.

An artifact handle includes:

  • schema version
  • opaque artifact id
  • canonical artifact directory
  • canonical project root
  • request snapshot digest
  • effective policy digest when available
  • creation time

Rail rejects forged or unsafe handles, including symlinked artifact directories, traversal, mismatched project roots, missing request snapshots, and digest mismatches.

Actor Runtime Policy

Rail loads operator defaults first. A target repository policy may only narrow the effective policy; it cannot enable tools, credentials, providers, approval behavior, mutation modes, resource ceilings, or network modes that defaults did not authorize.

The default policy disables host shell, filesystem, network, and MCP tools for actors. Direct target mutation is not allowed.

Sandbox And Patch Boundary

Actor work happens in an external sandbox. The target repository is not mutated until Rail validates and applies a patch bundle.

Patch bundles reject:

  • absolute paths
  • path traversal
  • writes into .harness/artifacts unless explicitly allowed for evidence
  • symlink and hardlink escapes
  • binary writes unless policy allows them
  • executable bit changes unless policy allows them
  • stale target tree digests

Validation evidence is tied to the applied patch and target tree digest. Evaluator pass is blocked when required validation is missing, failed, stale, actor-invented, or mutation-unsafe.

Credentials

SDK credentials come from approved operator-controlled sources only. Target-local credential files and target-local environment requests are rejected.

Actor environments receive the minimum necessary variables. Secret canaries and common API key shapes are redacted from traces, normalized events, validation logs, runtime evidence, terminal summaries, and result projection.

Project-Local .harness

Each target repository owns its project-local .harness/ state:

  • requests and request snapshots
  • artifacts
  • actor prompts
  • templates
  • policy overlays
  • reviewed learning state

The layout remains explicit and reviewable, but normal users interact through the Rail skill and Python API rather than hand-written files.

Contributor Notes

This repository owns the Python Rail Harness Runtime, bundled Rail skill, default .harness assets, tests, examples, and design documents.

Use the local release gate before treating this control-plane repository as release-ready:

scripts/release_gate.sh

The gate proves the Rail runtime, package build, package asset inspection, installed-wheel smoke, docs guards, removed-surface guards, lint, and typing checks for this repository. It is not a downstream target application success proof.

Optional live SDK smoke is operator-gated. Set RAIL_ACTOR_RUNTIME_LIVE_SMOKE=1 with an operator-controlled OPENAI_API_KEY; the release gate then enables RAIL_ACTOR_RUNTIME_LIVE=1 for the live smoke only.

Installation

The Python package distribution is rail-sdk. It exposes the Rail Python API, bundled Rail skill assets, and setup helpers. There is no command surface as the product contract; wrapper UX may exist later only as a thin layer over the same API.

Install the package and configure the operator SDK credential:

export OPENAI_API_KEY=...
uv tool install rail-sdk

Install or refresh the local Rail skill, then check readiness:

rail migrate
rail doctor

If an older Homebrew rail binary is still first on PATH, use the package name entrypoint first:

rail-sdk migrate
rail-sdk doctor

Then remove the old formula with the command reported by rail doctor. The usual cleanup is:

brew uninstall rail
brew cleanup rail

After setup, open the target repository and use the Rail skill with a natural-language task:

Use the Rail skill.
Fix the profile loading bug.

Normal users do not need to set runtime feature flags or repeat the target path when they are already working inside the target repository.

Release Publishing (operator)

For public release publication, use one changelog source only:

Release is now triggered by a version tag, not by local upload commands:

Homebrew is used only for cleanup of old installs; it does not drive release.

  1. Add a release entry in CHANGELOG.md at the top with: ## v${VERSION} - <YYYY-MM-DD>.
  2. Set pyproject.toml version to the same ${VERSION} as that changelog heading.
  3. Run the local release gate once in a clean repo.
  4. Commit those changes, create a tag, and push.
VERSION=0.6.0
scripts/release_gate.sh
git commit -am "Prepare v${VERSION} release"
git tag "v${VERSION}"
git push origin main
git push origin "v${VERSION}"

A GitHub tag push (v*) triggers .github/workflows/publish.yml. The workflow validates:

  • pyproject.toml version equals tag version
  • the top CHANGELOG.md entry matches the tag version
  • local release gate
  • package build
  • PyPI publish using PYPI_API_TOKEN
  • GitHub release notes generated from the same CHANGELOG.md section

Use CHANGELOG.md as the only user-facing release note/changelog source. After publish, users install the version they need:

uv tool install rail-sdk==${VERSION}

If you need to release manually, use uv and twine with your token:

uv build
TWINE_USERNAME=__token__ TWINE_PASSWORD=<pypi_token> uvx twine upload dist/*

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rail_sdk-0.6.0.tar.gz (55.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rail_sdk-0.6.0-py3-none-any.whl (82.5 kB view details)

Uploaded Python 3

File details

Details for the file rail_sdk-0.6.0.tar.gz.

File metadata

  • Download URL: rail_sdk-0.6.0.tar.gz
  • Upload date:
  • Size: 55.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rail_sdk-0.6.0.tar.gz
Algorithm Hash digest
SHA256 420584c4a195a1941e36d487a85d6d5e4ab2df4d24d41e84d934ab4f8b639e4b
MD5 f7e7539276ba48f179dd28fd50fbb4ad
BLAKE2b-256 b9aef07102e97f53586bdf612218c525a1bb53295561325b9fb60a0d5c9fc89e

See more details on using hashes here.

File details

Details for the file rail_sdk-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: rail_sdk-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 82.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rail_sdk-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e17093c95b9ae44f7d943710e4f7d83ddf12c04493d2f81645d6f343306a4c9f
MD5 104ab0b8557b678ed2887e14cd664727
BLAKE2b-256 a855aa96ca26bf90c5c5ecf2261eb3979236cca7f90d05db070ac18ea4de22f3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page