Long-running task management plugin for Hermes Agent
Project description
SagTask
A Hermes Agent standalone user plugin for long-running, multi-phase tasks with structured methodology execution, subagent orchestration, and cross-session recovery. Each task gets its own Git repository with full version control.
SagTask is NOT a memory provider. It coexists with any memory system and injects task context via the
pre_llm_callhook.
Multi-Agent Collaboration
Hermes supports multiple profiles (agents) that share the same ~/.hermes/sag_tasks/ directory — all agents collaborate on the same pool of tasks. But each agent tracks its own active task independently:
~/.hermes/
├── plugins/sagtask/ ← Default profile plugin
├── profiles/
│ ├── hbuilder/plugins/sagtask/ ← Profile "hbuilder" plugin
│ └── hexpert/plugins/sagtask/ ← Profile "hexpert" plugin
└── sag_tasks/ ← Shared task pool (all agents)
├── .active_tasks.json ← Per-profile active task tracking
├── my-project/ ← Task Git repo (shared)
└── another-task/ ← Task Git repo (shared)
.active_tasks.json tracks which task each agent is working on:
{
"default": "my-project",
"hbuilder": "sagtask-devop",
"hexpert": null
}
How it works:
- Each profile's
SagTaskPluginderives its profile ID from the_hermes_homepath (~/.hermes/profiles/<name>) _active_task_idis a@propertythat transparently reads/writes the correct entry in the dict- Zero changes needed in handlers or hooks — the property abstraction handles everything
- Legacy
.active_taskfiles are auto-migrated on first read
Installation: install.sh and /sagtask update automatically install the plugin to all profiles:
curl -fsSL https://raw.githubusercontent.com/ethanchen669/sagtask/main/install.sh | bash
# Installs to ~/.hermes/plugins/sagtask/ + every ~/.hermes/profiles/*/plugins/sagtask/
Quick Install
curl -fsSL https://raw.githubusercontent.com/ethanchen669/sagtask/main/install.sh | bash
Or manually:
git clone https://github.com/ethanchen669/sagtask.git ~/.hermes/plugins/sagtask
# Restart your Hermes gateway to load the plugin
Self-Update
SagTask has a built-in /sagtask slash command:
/sagtask update → Check GitHub releases, download + install to all profiles
/sagtask version → Show current installed version
/sagtask help → Show usage
Tools (20)
Task Lifecycle
| Tool | Description |
|---|---|
sag_task_create |
Create task with phased steps/gates, init Git + GitHub repo |
sag_task_status |
Show current phase/step/pending gates |
sag_task_advance |
Move to next step/phase (blocks if verification fails) |
sag_task_pause |
Snapshot execution context for later resume |
sag_task_resume |
Restore from most recent paused execution |
sag_task_approve |
Submit approval decision for a pending gate |
sag_task_list |
List all tasks with status |
Planning & Execution
| Tool | Description |
|---|---|
sag_task_plan |
Generate structured subtask plan for the current step |
sag_task_plan_update |
Update subtask status (done/failed), sync progress |
sag_task_dispatch |
Build subagent context for a subtask, optional worktree isolation |
sag_task_verify |
Run verification commands, record pass/fail |
sag_task_review |
Build structured review prompt (step/phase/full scope) |
Methodology
| Tool | Description |
|---|---|
sag_task_brainstorm |
Design exploration → option selection workflow |
sag_task_debug |
Systematic debugging: reproduce → diagnose → fix |
sag_task_metrics |
Query verification stats, coverage trends, throughput |
Rules
| Tool | Description |
|---|---|
sag_task_rules |
Manage development rules: list/add/update/remove/toggle |
12 built-in rules auto-loaded on task creation. Smart context injection selects relevant rules based on methodology and phase. See Development Rules System for details.
Git Operations
| Tool | Description |
|---|---|
sag_task_commit |
Stage all + commit with message |
sag_task_branch |
Create + push new branch |
sag_task_git_log |
Show recent commit history |
sag_task_relate |
Link two tasks as cross-pollination partners |
Architecture
src/sagtask/
├── __init__.py ← register(), re-exports
├── plugin.py ← SagTaskPlugin class, layered context injection
├── hooks.py ← pre_llm_call, on_session_start
├── schemas.py ← 20 tool JSON schemas
├── _utils.py ← constants, shared helpers
├── rules.py ← 12 default rules, CRUD, smart context selection
└── handlers/
├── __init__.py ← _tool_handlers dispatch dict
├── _lifecycle.py ← create, status, advance, pause, resume, approve, list
├── _plan.py ← plan, plan_update, verify, brainstorm, debug
├── _orchestration.py← dispatch, review, context builders
├── _metrics.py ← metrics query handler
└── _git.py ← commit, branch, git_log, relate
Plugin Registration
register(ctx)
├── ctx.register_tool("sag_task_*", ...) × 20
├── ctx.register_hook("pre_llm_call", ...) # layered context injection
└── ctx.register_hook("on_session_start", ...) # restore active task
Context Injection — Layered System
SagTask injects a compact, adaptive context block before each LLM call. The system minimizes token usage by only including information that has changed or is urgently needed.
| Layer | Content | Frequency |
|---|---|---|
| L0 | [SagTask] task=X status=active phase=P step=S |
Every turn |
| L1 | Phase/step names, pending gates | On change + blocking gates |
| L1.5 | Artifacts summary | On change |
| L2 | Methodology phase, plan progress, failures | On change |
| L2.5 | Selected development rules (smart filtering) | On change + first turn |
| L3 | Verification status, metrics (pass rate, coverage) | On change + blocking |
| L4a | Related tasks hint ("2 tasks available") | When relationships exist |
| L4b | Related task details | First turn, step switch, user intent |
Cache: Per-session per-task cache with context hashing. Stable state → single L0 line (~50 tokens). Changed state → relevant layers expand.
Methodology System
Each step can declare a methodology that guides execution:
| Type | Workflow |
|---|---|
tdd |
RED → GREEN → REFACTOR cycle, auto-transitions on verify |
brainstorm |
Generate 3+ options → user selects → implement |
debug |
Reproduce → diagnose (hypothesis) → fix |
plan-execute |
Plan subtasks → execute sequentially → verify each |
none |
No methodology constraint (default) |
Development Rules System
12 built-in rules guide agent behavior across all tasks. Rules use a global defaults + per-task overrides pattern.
Storage
- Global rules:
~/.hermes/sag_tasks/.rules.json— shared across all tasks - Per-task overrides:
.sag_task_state.json→rulesfield — task-specific additions/toggles
The 12 Rules
| # | Rule | Category |
|---|---|---|
| 1 | Think Before Editing. State assumptions explicitly; ask when uncertain; present options when ambiguous. | thinking |
| 2 | Simplicity first. Minimum code that solves the problem. No speculative design, no unrequested features. | thinking |
| 3 | Surgical changes. Touch only necessary code; don't refactor unrequested parts; match existing style. | process |
| 4 | Goal-driven. Define verification criteria and loop until met, don't follow rigid step sequences. | process |
| 5 | LLM for judgment only. Use LLM for classification, drafting, summarization, extraction. Use code for routing, retries, deterministic transforms. | quality |
| 6 | Manage Context Deliberately. Treat context as a limited resource. For long tasks, maintain compact checkpoints: objective, files changed, commands run, artifacts produced, unresolved assumptions, next step. Load targeted files first; avoid broad dumps. Never skip required reading or verification to save context. | quality |
| 7 | Surface conflicts, don't average them. When patterns contradict, pick one and explain; flag the other for cleanup. | thinking |
| 8 | Read Before Writing. Check exports, callers, shared utilities before adding code. Ask when unclear. | process |
| 9 | Tests encode intent. Tests should encode why behavior matters, not just pass when business logic changes. | quality |
| 10 | Checkpoint every step. Summarize progress, verify state, list remaining work. Stop and restate position when lost. | process |
| 11 | Match codebase conventions. Consistency over personal preference. Raise disagreements explicitly, don't silently change style. | style |
| 12 | Fail loudly. Skipping tests and saying 'tests pass' is misleading. Surface uncertainty by default. | quality |
Smart Context Injection
Rules are injected into pre_llm_call context at L2.5, filtered by current state:
| Trigger | Rules Injected |
|---|---|
methodology = tdd |
rule-9 (tests encode intent) |
methodology = brainstorm |
rule-1 (think first), rule-7 (surface conflicts) |
methodology = debug |
rule-12 (fail loudly), rule-4 (goal-driven) |
| Pending gates | rule-3 (surgical changes), rule-10 (checkpoint) |
| First turn | All 12 rules |
| No special state | rule-1, rule-2, rule-12 (core three) |
Managing Rules
# List current task's rules
sag_task_rules action: list
# Add a custom rule (task-level)
sag_task_rules action: add content: "Use type hints on all functions" task_id: "my-project" category: "quality"
# Add a global rule
sag_task_rules action: add content: "All PRs need 2 approvals" category: "process"
# Toggle a rule on/off
sag_task_rules action: toggle rule_id: "rule-6" task_id: "my-project"
# Remove a custom rule
sag_task_rules action: remove rule_id: "rule-custom-abc123" task_id: "my-project"
Orchestration
sag_task_plan → Generate subtasks from step description
sag_task_dispatch → Build subagent context, optional git worktree
└─ subagent executes → sag_task_plan_update(status="done")
sag_task_review → Spec compliance + quality review context
sag_task_verify → Run commands, record results to metrics
sag_task_advance → Move to next step (blocks if must_pass fails)
Metrics
Append-only event log (.sag_metrics.jsonl) tracks:
- Verification runs (pass/fail, exit codes, coverage)
- Subtask completions
- Step advances, dispatches, pauses/resumes
Query with sag_task_metrics for pass rates, coverage trends, and subtask throughput.
Storage Layout
~/.hermes/sag_tasks/
├── .active_tasks.json ← Per-profile active task tracking
├── .rules.json ← Global development rules (shared)
└── <task_id>/
├── .git/ ← Task Git repo
├── .gitignore
├── .sag_task_state.json ← Machine-readable state (git-ignored)
├── .sag_plans/ ← Subtask plans (git-tracked)
│ └── <step_id>.json
├── .sag_metrics.jsonl ← Metrics event log (git-ignored)
├── .sag_artifacts/ ← Generated artifacts (git-ignored)
├── .sag_executions/ ← Pause snapshots (git-ignored)
├── .sag_worktrees/ ← Isolated subtask worktrees (git-ignored)
└── src/, tests/, docs/ ← User code (git-tracked)
Development
# Run tests
python -m pytest tests/ -v
# Run with coverage
python -m pytest tests/ --cov=src/sagtask --cov-report=term-missing
# Install for local Hermes dev
./dev-install.sh
# Build release tarball
bash scripts/build-release.sh 2.0.0
# Bump version across all files
bash scripts/bump-version.sh 2.1.0
Release Process
bash scripts/bump-version.sh X.Y.Z
# Update CHANGELOG.md
git add -A && git commit -m "chore: release vX.Y.Z"
git tag vX.Y.Z && git push origin main --tags
# GitHub Actions builds artifact + creates release automatically
License
MIT
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 sagtask-2.2.1.tar.gz.
File metadata
- Download URL: sagtask-2.2.1.tar.gz
- Upload date:
- Size: 46.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1d25932936b464ecfa56ebf6e3820cd9f1abfdf1b79dde3d8daf959c796c7e13
|
|
| MD5 |
0b8d3e1c87d9905e5ada967352b64151
|
|
| BLAKE2b-256 |
b61af1892fb811cd345affdaf294c46e3eb4be464fdd180363cd348e39ddb177
|
Provenance
The following attestation bundles were made for sagtask-2.2.1.tar.gz:
Publisher:
release.yml on ethanchen669/sagtask
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sagtask-2.2.1.tar.gz -
Subject digest:
1d25932936b464ecfa56ebf6e3820cd9f1abfdf1b79dde3d8daf959c796c7e13 - Sigstore transparency entry: 1709450068
- Sigstore integration time:
-
Permalink:
ethanchen669/sagtask@14acfe87c2378f711df2938cba9e0927d4efba33 -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/ethanchen669
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@14acfe87c2378f711df2938cba9e0927d4efba33 -
Trigger Event:
push
-
Statement type:
File details
Details for the file sagtask-2.2.1-py3-none-any.whl.
File metadata
- Download URL: sagtask-2.2.1-py3-none-any.whl
- Upload date:
- Size: 55.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e824610e1d6e90acd18ba644f860c0c5a2a12085547765ef90538e04891dcd5d
|
|
| MD5 |
a97ee7985a32577123519d9814035423
|
|
| BLAKE2b-256 |
e43073bffe9ecf3faaa20cfa61144575ff1630cad95122cc7f15bb72354009ba
|
Provenance
The following attestation bundles were made for sagtask-2.2.1-py3-none-any.whl:
Publisher:
release.yml on ethanchen669/sagtask
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sagtask-2.2.1-py3-none-any.whl -
Subject digest:
e824610e1d6e90acd18ba644f860c0c5a2a12085547765ef90538e04891dcd5d - Sigstore transparency entry: 1709450255
- Sigstore integration time:
-
Permalink:
ethanchen669/sagtask@14acfe87c2378f711df2938cba9e0927d4efba33 -
Branch / Tag:
refs/tags/v2.2.1 - Owner: https://github.com/ethanchen669
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@14acfe87c2378f711df2938cba9e0927d4efba33 -
Trigger Event:
push
-
Statement type: