Trajectory Refinement Testing (TRT) for deterministic agent CI
Project description
Trajectly
Deterministic regression testing for AI agents, powered by Trajectory Refinement Testing (TRT).
Trajectly records a known-good baseline, replays against deterministic fixtures, and tells you exactly where behavior diverged.
Install
python -m pip install trajectly
python -m trajectly --version
Expected output cue:
trajectly, version X.Y.Z
30-Second Quickstart
Use the standalone procurement demo with pre-recorded fixtures (no API keys required):
git clone https://github.com/trajectly/procurement-approval-demo.git
cd procurement-approval-demo
python3.11 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m trajectly run specs/trt-procurement-agent-regression.agent.yaml --project-root .
python -m trajectly report
python -m trajectly repro
python -m trajectly shrink
Expected exits for this intentional regression flow:
run ...regression...->1(FAIL)report->0repro->1(replays same failing run)shrink->0
Observed output excerpts from a fresh run (March 5, 2026):
# run ...regression...
- `trt-procurement-agent`: regression
- trt: `FAIL` (witness=10)
# report
Source: $PROJECT_ROOT/.trajectly/reports/latest.md
# repro
Repro command: python -m trajectly run "$PROJECT_ROOT/specs/trt-procurement-agent-regression.agent.yaml" --project-root "$PROJECT_ROOT"
# shrink
Shrink completed and report updated with shrink stats.
Artifacts to expect after running the flow:
$PROJECT_ROOT/.trajectly/reports/latest.md$PROJECT_ROOT/.trajectly/reports/latest.json$PROJECT_ROOT/.trajectly/repros/<spec>.json$PROJECT_ROOT/.trajectly/repros/<spec>.counterexample.reduced.trace.jsonl
For full step-by-step command/output walkthroughs, use docs/trajectly.md.
What Trajectly Checks
TRT evaluates behavior, not just output text:
- Contract compliance: allow/deny rules, sequence constraints, budgets, network, data leak, args.
- Refinement: baseline tool-call skeleton must remain a subsequence of the new run.
- Witness resolution: report the earliest failing event index (0-based trace index).
Result: stable PASS/FAIL in CI with deterministic repro.
Typical Workflow
python -m trajectly init
python -m trajectly record specs/*.agent.yaml --project-root .
python -m trajectly run specs/*.agent.yaml --project-root .
python -m trajectly report
Typical clean-run cue:
- `my-agent`: clean
- trt: `PASS`
Latest report: $PROJECT_ROOT/.trajectly/reports/latest.md
Failure triage loop:
python -m trajectly repro
python -m trajectly shrink
Typical failing-run cue:
Repro command: python -m trajectly run "$PROJECT_ROOT/specs/my-agent.agent.yaml" --project-root "$PROJECT_ROOT"
Shrink completed and report updated with shrink stats.
SDK Options
Trajectly supports two instrumentation styles.
Option A: Decorators and adapters
from trajectly.sdk import tool, llm_call
@tool("fetch_ticket")
def fetch_ticket(ticket_id: str) -> dict:
return {"id": ticket_id, "status": "open"}
@llm_call(provider="openai", model="gpt-4o")
def classify_ticket(text: str) -> str:
...
You can also use framework adapters like openai_chat_completion, gemini_generate_content, and langchain_invoke.
Option B: Declarative graph API (trajectly.App)
import trajectly
app = trajectly.App(name="research-agent")
@app.node(id="search_engine", type="tool")
def search(query: str) -> dict:
...
@app.node(id="summarizer", type="llm", depends_on=["search_engine"], provider="openai", model="gpt-4o")
def summarize(search_engine: dict) -> str:
...
@app.node(id="format_response", type="transform", depends_on=["summarizer"])
def format_response(summarizer: str) -> dict:
return {"answer": summarizer}
if __name__ == "__main__":
outputs = app.run(input_data={"query": "Why is the sky blue?"})
print(outputs["format_response"])
The graph layer uses the same SDKContext instrumentation path and trace event types (tool_called, tool_returned, llm_called, llm_returned, agent_step). No CLI changes are required.
CI Integration
Any CI
python -m pip install trajectly
python -m trajectly run specs/*.agent.yaml --project-root .
python -m trajectly report --pr-comment > comment.md
What to expect:
run exit code:
- 0 when all specs are clean
- 1 when regressions are detected
GitHub Actions
The canonical action is published at trajectly/trajectly-action:
name: Agent Regression Tests
on: [push, pull_request]
jobs:
trajectly:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: trajectly/trajectly-action@v1
with:
spec_glob: "specs/*.agent.yaml"
project_root: "."
Notes:
comment_pris off by default. Enable it only when you want PR comments and grantpull-requests: write.- The in-repo path
./github-actionis a temporary compatibility wrapper and will be removed after one release cycle.
See docs/ci_github_actions.md for input options and full behavior.
Architecture at a Glance
| Layer | Purpose | Key modules |
|---|---|---|
core |
TRT evaluation, traces, fixtures, contracts | core/trt, core/contracts.py, core/refinement |
cli |
Command orchestration and reporting | cli/commands.py, cli/engine.py |
sdk |
Runtime instrumentation + graph API | sdk/context.py, sdk/adapters.py, sdk/graph.py |
Documentation
- Full reference
- Architecture
- CI: GitHub Actions
- Security policy
- Contributing guide
- Support Escalation Demo (standalone)
- Procurement Approval Demo (standalone)
Contributing
For a friendly step-by-step contribution guide, see CONTRIBUTING.md.
git clone https://github.com/trajectly/trajectly.git
cd trajectly
python -m pip install -e ".[dev]"
pytest tests/
ruff check .
mypy src
License
Apache 2.0 -- see LICENSE.
Community
- Questions and use-case discussions: https://github.com/trajectly/trajectly/discussions
- Security reports (private): https://github.com/trajectly/trajectly/security/advisories/new
Support Trajectly
If Trajectly is useful to your work, please give the repository a star ⭐: https://github.com/trajectly/trajectly/stargazers
Project details
Release history Release notifications | RSS feed
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 trajectly-0.4.2.tar.gz.
File metadata
- Download URL: trajectly-0.4.2.tar.gz
- Upload date:
- Size: 89.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9e3854515d7b69fa921b371c35e2812f361b0d6c82f0195d526dad50c0db416
|
|
| MD5 |
3fb5810aa247c8f489238adcba135a95
|
|
| BLAKE2b-256 |
e0471c6c212e81a8bf7136a15de409da8dc805a80f4e9762a58dd9f74087dde1
|
File details
Details for the file trajectly-0.4.2-py3-none-any.whl.
File metadata
- Download URL: trajectly-0.4.2-py3-none-any.whl
- Upload date:
- Size: 118.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
059fa0f58dd7e124b03a31cd451af65bb024a1ccb311cd34fff65c2e904f74d6
|
|
| MD5 |
d609e1318b1fc9a7ce5cbd8b6c1bd222
|
|
| BLAKE2b-256 |
250ed3b22341bd514f7cf725724410e0fd2c760a3e5b1a35ae0f99dea6935c28
|