Skip to main content

A generic Claude Code agent harness: iterative task execution, Slack integration, and persistent memory management.

Project description

TigerHarness

PyPI Python License

A generic Claude Code agent harness: iterative task execution, Slack integration, and persistent memory management.

Sub-packages

Package Description
tigerharness.agent_sdk Backend-agnostic agent SDK. Same caller code, swappable runtimes: claude -p subprocess, Anthropic's claude-agent-sdk, OpenAI's openai-agents (planned).
tigerharness.task_runner Fire-and-forget iterative task execution. Drives a persona through N Claude turns with periodic /compact.
tigerharness.slack_bridge Slack Socket Mode bridge. Forwards DMs to a claude -p backend and posts replies back to the thread.
tigerharness.tiger_memory Persistent agent memory: archive, journal, briefing with lazy rebuild, kind-decay must-memorize, and drill-down.

Installation

Pick the strategy that matches how you want to use tigerharness:

Option A — Scope it to one folder (recommended for teams)

Best when you want a self-contained teams/ directory that owns its own tigerharness install — nothing global, nothing borrowed:

mkdir -p ~/projects/teams && cd ~/projects/teams
uv init --bare                       # creates a minimal pyproject.toml
uv add 'tigerharness[all]'           # adds dep, creates .venv + uv.lock
uv run tigerharness init             # interactive team scaffolder

tigerharness only exists inside this folder's .venv; from then on you invoke it with uv run tigerharness ....

Option B — Install as a global CLI

Best when you want tigerharness available everywhere, like git or gh:

uv tool install 'tigerharness[all]'  # one-time; puts `tigerharness` on PATH
tigerharness init                    # works from any directory

Equivalent with pipx: pipx install 'tigerharness[all]'.

Option C — Traditional pip into an active venv

python -m venv .venv && source .venv/bin/activate
pip install 'tigerharness[all]'
tigerharness init

Choosing extras

tigerharness has zero hard dependencies by design. Optional features are gated behind extras so you don't pay disk/install cost for things you don't use:

Extra Pulls in Enables / required for
(none) init scaffolder, dismiss teardown, task-runner with the default claude -p subprocess backend
[anthropic] claude-agent-sdk The official Claude Agent SDK backend (anthropic_sdk)
[slack] slack-bolt, aiohttp, python-dotenv slack-bridge (Slack Socket Mode DM bridge)
[memory] pyyaml tiger-memory (per-persona persistent memory; substring search only)
[memory-rag] pyyaml, fastembed, sqlite-vec tiger-memory with semantic search via local embeddings (free, ~50 MB model download on first use)
[memory-rag-openai] pyyaml, openai, sqlite-vec tiger-memory with semantic search via OpenAI embeddings (API key needed, no model download)
[all] union of everything above Everything works out of the box

Pick the union that matches what you'll use, e.g. 'tigerharness[slack,memory,anthropic]' for a Slack-fronted agent with persistent memory and the official SDK backend.

Heads up: the install commands quote the extras ('tigerharness[all]') because zsh treats [ as a glob character. In bash you can drop the quotes, but quoting always works.

Quick start

Scaffold a team and its first persona

tigerharness init is interactive — it walks you through:

  1. Multi-team Slack mode (recommended for new setups) — opt in or out.
  2. Persona name + team.
  3. Slack .env template + memory config (optional toggles).
  4. Slack user-ID allowlist for the team's bridge bot (optional).

The memory store is auto-initialized for each new persona and the Claude Code transcripts path is auto-detected from the team root, so the user never has to come back and edit placeholders. Every persona always belongs to a team, and a team is a self-contained directory:

tigers/
├── configs/
│   ├── personas.yaml              # team registry (auto-updated)
│   └── .env                       # Slack tokens (gitignored)
├── skills/
│   └── README.md                  # drop team-shared skills here
├── personas/
│   ├── chief/
│   │   └── prompt.md              # the persona's system prompt
│   └── scout/
│       └── prompt.md
└── memories/
    ├── chief/
    │   └── tiger-memory.config.yaml   # per-persona memory config
    └── scout/
        └── tiger-memory.config.yaml
# Fully interactive — prompts for persona name, team, slack/memory opts
tigerharness init

# Non-interactive — creates team 'tigers' with persona 'chief'
tigerharness init --persona chief --team tigers --yes

# Add a second persona to the same team
tigerharness init --persona scout --team tigers --yes

# Skip Slack or memory generation
tigerharness init --persona chief --team tigers --no-memory --no-slack --yes

Tear down a team or persona

tigerharness dismiss is the symmetric counterpart of init — it removes a team (or a single persona inside a team) and all of the associated state: configs, prompts, per-persona memory data, the multi-team index entry, and — for the last team in a multi-team setup — the slack-bridge-multi systemd user unit too.

The command is always interactive and gated behind two confirmations (a backup acknowledgement and a type-the-name check), so it's hard to fire by accident:

# Walks you through: pick team-or-persona → preview → backup confirm
# → type the name → execute. Out of scope: deleting the Slack app on
# api.slack.com (the command prints a manual reminder).
tigerharness dismiss

# Same flow but exits after the preview — useful for checking what
# would happen without touching anything.
tigerharness dismiss --dry-run

Refusals are deliberate, not bugs:

  • Dismissing the last persona of a team is refused — use team-level dismissal instead, or add another persona first.
  • Dismissing a persona that's the team's default_persona in the Slack-bridge fragment is refused — pick a new default in the fragment first, then re-run.

Task runner

# 1. Point tigerharness at your team's persona registry
export TIGERHARNESS_PERSONAS_CONFIG=./tigers/configs/personas.yaml

# 2. Assign a task (5 iterations)
python -m tigerharness.task_runner assign \
    --to chief \
    --prompt "Research the latest developments in solar energy" \
    --iters 5

# 3. Check status
python -m tigerharness.task_runner list

# 4. View logs
python -m tigerharness.task_runner logs <task-id>

Slack bridge

# 1. Fill in your Slack tokens in tigers/configs/.env (from api.slack.com)
#    SLACK_APP_TOKEN=xapp-...
#    SLACK_BOT_TOKEN=xoxb-...
#    ALLOWED_SLACK_USER_IDS=U0123ABC

# 2. Run the bridge
python -m tigerharness.slack_bridge

Multi-team mode — one bridge process can serve N teams (one Slack app per team, separate bot identities, separate threads.json). Opt in by creating slack-bridge.yaml in your teams dir; subsequent tigerharness init runs auto-register each team. See docs/slack-bridge.md#multi-team-mode for the full setup.

Tiger memory

Each persona has its own memory config under tigers/memories/<persona>/tiger-memory.config.yaml. Edit it to point at your Claude Code project path, then:

--config is a top-level option for the tiger-memory sub-command, so it must appear before the verb:

# Save typing — the same path is reused everywhere
CFG=tigers/memories/chief/tiger-memory.config.yaml

# 1. Initialize the memory store (per persona)
tigerharness tiger-memory --config $CFG init

# 2. Bootstrap (one-time backfill from existing transcripts)
tigerharness tiger-memory --config $CFG bootstrap --dry-run
tigerharness tiger-memory --config $CFG bootstrap

# 3. Rebuild (incremental, run after each session)
tigerharness tiger-memory --config $CFG rebuild

# 4. Search memory
tigerharness tiger-memory --config $CFG search "solar energy"

# 5. Pin a must-memorize fact
tigerharness tiger-memory --config $CFG pin "Prefers solar over wind"

Configuration

All paths are resolved from environment variables -- no hardcoded paths.

Variable Default Description
TIGERHARNESS_STATE_DIR ~/.local/state/tigerharness-tasks/ Task runner state directory
TIGERHARNESS_PERSONAS_DIR (none) Directory containing <name>.md prompt files
TIGERHARNESS_SLACK_ENV .env Path to slack-bridge .env file
TIGERHARNESS_AGENT_CWD . Working directory for the Claude agent
TIGERHARNESS_AGENT_PROMPT (none) Path to the agent's system prompt
TIGERHARNESS_SLACK_BRIDGE_DIR (none) Path to slack-bridge service dir (for notify CLI)
TIGERHARNESS_ATTACHMENT_DIR /tmp/slack-attachments Where to stage downloaded files
TIGER_MEMORY_CONFIG (none) Path to tiger-memory YAML config
TIGER_MEMORY_CLI (none) Path to tiger-memory CLI binary

Examples

See examples/ for a fully-populated sample team folder (examples/tigers/) and standalone reference configs:

Requirements

  • Python 3.11+
  • For the default claude_p backend: the Claude Code CLI (claude) on PATH.
  • For the anthropic_sdk backend: install with [anthropic] extra; pulls in claude-agent-sdk.

License

MIT

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

tigerharness-0.2.1.tar.gz (357.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tigerharness-0.2.1-py3-none-any.whl (210.6 kB view details)

Uploaded Python 3

File details

Details for the file tigerharness-0.2.1.tar.gz.

File metadata

  • Download URL: tigerharness-0.2.1.tar.gz
  • Upload date:
  • Size: 357.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tigerharness-0.2.1.tar.gz
Algorithm Hash digest
SHA256 e4886cd0221d99643e89cec6231e824ee75678cf963c0d07ee055af5adbfaaec
MD5 c8955e560321fc3d85d01a7b851943bb
BLAKE2b-256 72c2d2187b9a9ced16266cf71355d9d468fbc99d53a06f7a4323bb27ecdb3bd8

See more details on using hashes here.

Provenance

The following attestation bundles were made for tigerharness-0.2.1.tar.gz:

Publisher: release.yml on DingyuZhou/TigerHarness

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file tigerharness-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: tigerharness-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 210.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tigerharness-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 fd0e514e003bf18d5952c32df6fbdd7541152c3103e88f4f3db81e26efd38ab5
MD5 8abdb1bc5d831b42781f894cba4d35b7
BLAKE2b-256 72b9f0cafaf79f6ce7998629fd99b6341371cf2fffc64ab477137dfe33369717

See more details on using hashes here.

Provenance

The following attestation bundles were made for tigerharness-0.2.1-py3-none-any.whl:

Publisher: release.yml on DingyuZhou/TigerHarness

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page