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/artifactsunless 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.
- Add a release entry in
CHANGELOG.mdat the top with:## v${VERSION} - <YYYY-MM-DD>. - Set
pyproject.tomlversion to the same${VERSION}as that changelog heading. - Run the local release gate once in a clean repo.
- 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.tomlversion equals tag version- the top
CHANGELOG.mdentry matches the tag version - local release gate
- package build
- PyPI publish using
PYPI_API_TOKEN - GitHub release notes generated from the same
CHANGELOG.mdsection
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
420584c4a195a1941e36d487a85d6d5e4ab2df4d24d41e84d934ab4f8b639e4b
|
|
| MD5 |
f7e7539276ba48f179dd28fd50fbb4ad
|
|
| BLAKE2b-256 |
b9aef07102e97f53586bdf612218c525a1bb53295561325b9fb60a0d5c9fc89e
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e17093c95b9ae44f7d943710e4f7d83ddf12c04493d2f81645d6f343306a4c9f
|
|
| MD5 |
104ab0b8557b678ed2887e14cd664727
|
|
| BLAKE2b-256 |
a855aa96ca26bf90c5c5ecf2261eb3979236cca7f90d05db070ac18ea4de22f3
|