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 provider-selected execution boundary for bounded actor work. The default local provider is codex_vault; openai_agents_sdk remains optional for operator/API-key environments. Each actor 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."],
}

request = rail.specify(draft)
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

The default codex_vault path uses Rail-owned Codex auth configured through rail auth login and checked with rail auth doctor. openai_agents_sdk credentials are optional operator-controlled inputs for explicit API-key environments. 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:

uv tool install rail-sdk

Install or refresh the local Rail skill, prepare Rail-owned Codex auth, then check readiness:

rail migrate
rail auth login
rail auth doctor

openai_agents_sdk and OPENAI_API_KEY are optional operator paths, such as the opt-in live SDK smoke described above. They are not required for the default local codex_vault path.

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. Run the publish script.
./publish.sh v0.6.1

If the top CHANGELOG.md entry for that version is missing, the script creates one from changes since the previous release tag, then validates changelog quality. If the entry already exists, the script keeps it and validates it. After that it updates pyproject.toml and uv.lock, runs scripts/release_gate.sh, commits release metadata changes when needed, pushes main, and pushes the release tag.

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 through PyPI Trusted Publishing
  • 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}

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.5.tar.gz (76.5 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.5-py3-none-any.whl (106.8 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for rail_sdk-0.6.5.tar.gz
Algorithm Hash digest
SHA256 374feecf72ce52ab5fedbfd7b9e1251dd7ee2ef7f114041c507bdfdee029e921
MD5 b5aff7e21456a31992a889a015e0a20e
BLAKE2b-256 a51a20c57e4a2c9c3021a439a938b2459a805ac4c839ced261a6df5c1a608992

See more details on using hashes here.

Provenance

The following attestation bundles were made for rail_sdk-0.6.5.tar.gz:

Publisher: publish.yml on cutehackers/rail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

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

File metadata

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

File hashes

Hashes for rail_sdk-0.6.5-py3-none-any.whl
Algorithm Hash digest
SHA256 b471cc5ee423fcb8b3dad5ad4bf4225a394e63a481d9bef5f8bacf12955b78ca
MD5 aac2d05dd9f0a0950c1c6125394e7b2f
BLAKE2b-256 4d4421186174f20f0fcb3b72edda975b70de40b8bcd268cd095e8f8128c138b0

See more details on using hashes here.

Provenance

The following attestation bundles were made for rail_sdk-0.6.5-py3-none-any.whl:

Publisher: publish.yml on cutehackers/rail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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