Tina
Tina is an autonomous factory. It takes in clear work items from Jira, Github issues, etc and work on them to produce work that's relatively easily verified by a person.
pip install tina-cli
The track in that recording is examples/bug-triage/ — the config, the skill, and what each key does.
How is Tina different from an agent harness?
Tina is an orchestrator of sort.
It selects a work item, claims it, and calls an agent harness once with a one-shot prompt that I call a track.
The agent harness does the individual work item. Currently, I use pi, because it's small and relatively stable. I may use a different one in the future.
So what's the value of doing this approach instead?
With an agent harness, you have to sit there and steer it. Even if you have one shot prompts, you need to put those prompts in there.
For work items that are very self similar, you can instead make what I can a track.
Think of it like a runbook or a guide. You take several examples of work you have already done once and use them to describe to the agent what it should do.
Then upstream from this system in your ticketing system, you make work items for it.
Downstream from this system PRs get made or Confluence docs get write or whatver other outcome you want.
You just write tickets instead of driving around your agent to get work done.
This approach scales your attention better than having 5 simultaneous agent sessions running simultaenously, especially you enter production situations where you're quickly drowned by the amount of work coming your way.
High-level track approach
A track is Source -> Skill -> Result.
harness = "pi"
executor = "local"
[harnesses.pi]
command = ["pi", "-p", "@{prompt_file}"]
[bug]
source = "github"
repo = "acme/api"
labels = ["bug"] # or the full query = "repo:acme/api is:issue ..."
track = "triage"
result = "github:issue-comment"
A basic workflow:
tina validate # the config and every skill, statically
tina doctor # credentials, queries, harness, executor
tina dispatch --track bug --limit 5
tina run --track bug --item 4821
tina status --track bug
status derives both counts from the track's own query — once as dispatch runs
it, and once with its no:assignee clause swapped for the bot — so they are two
halves of one question and Tina keeps no state to go stale.
An external scheduler calls dispatch. Tina does not own scheduling — Cloud
Scheduler, EventBridge, k8s CronJob, systemd timers, and GitHub Actions all work
without Tina knowing about them.
Design
- Orchestration only. Tina never writes a result. The agent does, with its own tools.
- Harness agnostic. pi, Claude Code, and others are subprocess adapters. Tina
never parses harness stdout — the agent writes
outcome.jsonto a path Tina provides. - No persistent state. The tracker is the ledger. Workers claim items, and claimed items drop out of the query.
- Control plane in a file. Pause and throttle live in a control file
read fresh every dispatch, so whoever holds the pager can stop the factory
without a deploy. Per-track
max_concurrencyand a governor seam sit beside it. - No tracks included. Tracks are skills, installed with
napoln at image build time.
tina tracks --format jsonlists them so infrastructure can be derived from the same file the runtime reads.
Documentation
| Document | Description |
|---|---|
| docs/architecture.md | System design — tracks, dispatch/worker, adapters, outcome contract, v1 scope |
| docs/adr/ | Architecture decision records — the reasoning behind each design choice |
| CONTRIBUTING.md | Setup, the check loop, layout, how to add adapters, commit conventions |
Development
See CONTRIBUTING.md for the full guide.
just is the task runner (brew install just).
just setup # Install all dependencies
just check # Format check, lint, type check, tests
just fmt # Auto-fix formatting and lint
just test # Run tests
Without just:
uv sync --all-extras # Install all dependencies
uv run ruff format --check # Format check
uv run ruff check # Lint
uv run ty check # Type check
uv run pytest # Run tests
License
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 tina_cli-0.1.5.tar.gz.
File metadata
- Download URL: tina_cli-0.1.5.tar.gz
- Upload date:
- Size: 446.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
240a2dea8d47604f80aee761b5a954ff710b9e0ac1a856cfe644a2cc1b45f49c
|
|
| MD5 |
67c74f4497ead08348eb39b9707087f9
|
|
| BLAKE2b-256 |
5feef54b8f4f5813b4a1887a41574512317fc7b86af2d359406beca1da8dbf9f
|
File details
Details for the file tina_cli-0.1.5-py3-none-any.whl.
File metadata
- Download URL: tina_cli-0.1.5-py3-none-any.whl
- Upload date:
- Size: 77.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cebf6ea776b405da718fcb8c6b2ea5d0a26b7746159b4024cef553bac49f1ce1
|
|
| MD5 |
90ee7adb5d35fd2b5a3a43e7ab3e5758
|
|
| BLAKE2b-256 |
74a23ec40a605812f8261b6c11a0bc3737b21fb8acb5237ed37d82e2ad31938c
|