agent-junction
Failover and credential-routing for AI agent stacks. When one of your AI coding agents dies — quota exhausted, key rate-limited, service down — the junction detects it with a real probe, switches your work to a healthy standby, and fails back when the primary recovers. The decision to switch can be delegated to a zero-token classifier that holds on transient blips and switches on real collapse.
priority 0 (primary) priority 1 (standby)
┌────────────────┐ collapse ┌────────────────┐
│ agent "hermes"│ ─────────► │ agent "opencode"│
│ probe: tcp+proc│ ◄───────── │ probe: command │
└────────────────┘ recovered └────────────────┘
▲ ▲
└───── junction tick ─────┘
(cron every N minutes; no daemon required)
Why
Anyone running two or more agent systems (OpenCode, Claude Code, Codex, Gemini CLI, custom agents) eventually hits the same failure: an API key runs out mid-task and work silently stops until a human notices. The junction is the layer that notices for you — and it is agent-agnostic: it doesn't care what your agents are, only how to prove they're alive.
| Capability | Naive alternative | agent-junction |
|---|---|---|
| Health check | --version ping (proves nothing) |
live model round-trip, TCP probe, process scan |
| Failover decision | flip on first missed ping | optional zero-token gate classifies transient vs fatal |
| Safety | router failure = no failover | gate can delay a switch, never block one (streak bypass + fail-safe) |
| Forensics | "why did it switch?" | JSONL diagnostics + switch counter + calibrated decision trail |
| Ops model | another daemon to babysit | one bounded cron tick; no process to keep alive |
Install
pip install agent-junction # from PyPI (once published)
pip install "agent-junction[psutil]" # with process-probe support
# or straight from the repo:
pip install "git+https://github.com/hypnoticproductions/agent-junction.git"
Quick start
- Write a config (see
junction.example.json):
{
"agents": [
{ "name": "hermes", "priority": 0, "tcp": "127.0.0.1:9119" },
{ "name": "opencode", "priority": 1,
"command": ["opencode", "run", "--format", "json", "--model", "your/model", "Reply with the single word OK."],
"expect": "OK" }
],
"fail_streak_limit": 3,
"state_file": "junction-state.json"
}
- Probe and inspect:
junction --config junction.json status
junction --config junction.json doctor
- Schedule the bounded tick (cron, Task Scheduler, systemd timer):
*/5 * * * * junction --config /etc/junction/junction.json tick
*/5 * * * * junction --config /etc/junction/junction.json failback
The tick is a single pass: probe active → maybe switch. No daemon, no event loop, nothing to keep running between passes. Crashes are free.
The decision gate
By default every failure switches immediately (ImmediateSwitchGate).
If you run a System One / Laya escalation head, the junction will consult
it first:
"decision_gate": { "type": "laya", "module_path": "C:/path/to/chain", "escalate_threshold": 0.85 }
Two invariants hold no matter what the gate says:
- A gate can delay, never veto. If the gate holds but the agent keeps
failing, the streak counter force-switches after
fail_streak_limitconsecutive failures (~15 min at a 5-minute cadence). - Gate failure = switch. Any exception, missing chain, or placeholder decision resolves to switch. The decision layer is an optimization, not a dependency.
Probes
| Probe | Config key | Proves |
|---|---|---|
| TCP | "tcp": "host:port" |
a service is listening |
| Process | "process": {"name": "...", "exe_contains": "..."} |
the daemon is running |
| Command | "command": ["...", ...], "expect": "OK" |
end-to-end: binary, credentials, backing API |
Stack probes on one agent for cheap-to-expensive checking: the first listed is primary; the rest are fallbacks tried only when the primary fails.
Credentials
The junction never stores or logs credentials. Command probes inherit your
environment; load keys from your secret store in the cron wrapper, or
point command at a wrapper script that injects them. No key ever
appears in state, diagnostics, or the repo.
Development
pip install -e ".[test,psutil]"
pytest
Releasing
CI runs the test matrix (3 OSes × 4 Pythons) on every push. To publish a release to PyPI:
- Register the pending publisher once at
pypi.org/manage/account/publishing
— owner
hypnoticproductions, repoagent-junction, workflowpublish.yml(trusted publishing, no tokens stored anywhere). - Bump
versioninpyproject.toml, commit, then tag and push:git tag v0.1.0 && git push origin v0.1.0 - The publish workflow runs tests, builds, checks, and publishes.
Users then
pip install agent-junction.
Until PyPI publishing is registered, users can install directly:
pip install "git+https://github.com/hypnoticproductions/agent-junction.git"
License
MIT
Metadata
Release files for agent-junction 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agent_junction-0.1.0.tar.gz | 17.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_junction-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 32.2 kB
Release files / agent_junction-0.1.0.tar.gz
| Download URL | agent_junction-0.1.0.tar.gz |
|---|---|
| Size | 17.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
75b53d7e12025a090f0cc70e82bfe00da68ebf8985abed72f738ba5df22adcc6
|
|
BLAKE2b-256 checksum How to use checksums |
afdd68b5fbd754d698ff38674fbe00263d05e017cd5931d71e0b5891fe8702fd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / agent_junction-0.1.0-py3-none-any.whl
| Download URL | agent_junction-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3d1bdcc682272a39eb62be4c514ca836488d8966e9a92bce3448dfcb50f16bcd
|
|
BLAKE2b-256 checksum How to use checksums |
82cfddbc7f396e3ced7a5c37ad11c9c959d208e7269f2b1aeb369c1d6fd5aae9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for agent-junction 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.