Your own private AI β running for free on GitHub. No servers. No databases. No monthly bills.
β Star this repo if it helps you! β
Quick Start Β· How It Works Β· Story Β· Full Docs
IssueClaw is an AI assistant that lives inside your GitHub repo. You talk to it by opening issues. It responds by commenting. It remembers everything. It can even edit your code.
No servers. No databases. No monthly bills. Just GitHub Issues + GitHub Actions + your favorite LLM API.
1. You open an issue: "Build me a portfolio site"
2. IssueClaw reacts with π (it's working!)
3. IssueClaw creates the files, commits them to your repo
4. IssueClaw replies as a comment: "Done! Here's what I built..."
5. You comment back: "Add a dark mode toggle"
6. IssueClaw remembers the whole conversation and edits the files
Total cost: $0/month with Groq or Gemini's free tier.
git clone https://github.com/maruf009sultan/issueclaw.git
cd issueclawPick one (or more):
| Provider | Free? | Get Key | Best for |
|---|---|---|---|
| Groq | β | https://console.groq.com/keys | Quick chat (default mode) |
| Gemini | β | https://aistudio.google.com/app/apikey | Full agent mode (file editing) |
| Cerebras | β | https://inference.cerebras.ai/ | Fast agent mode |
| OpenRouter | β | https://openrouter.ai/keys | Many free models |
In your forked repo: Settings β Secrets and variables β Actions β New repository secret
- Name:
GROQ_API_KEY(orGEMINI_API_KEY,CEREBRAS_API_KEY, etc.) - Value: your API key
Go to the Actions tab β click "I understand my workflows, go ahead and enable them"
That's it! Open an issue and IssueClaw responds automatically.
IssueClaw has two modes:
Open an issue with no label β IssueClaw responds directly, like ChatGPT.
- Uses ~500 tokens per message
- Works perfectly with Groq's free tier (12K TPM)
- Perfect for: questions, explanations, quick help
Open an issue with the agent label β IssueClaw becomes a full coding agent.
- Can read files, edit files, run bash, commit to your repo
- Uses ~120,000 tokens per message
- Needs Gemini (1M TPM) or Cerebras (60K TPM) β Groq can't handle it
- Perfect for: "Build me a website", "Fix this bug", "Add a README"
Open an issue with the hatch label β bootstrap IssueClaw's personality.
IssueClaw will have a conversation with you to figure out its name, vibe, and emoji. Stored in state/personality.md β persists forever via git.
AI assistants are great, but they have problems:
- They're expensive β ChatGPT Plus is $20/month, Copilot is $10/month
- They forget everything β close the tab, lose the context
- They can't touch your code β copy-paste workflow is painful
- They need servers β self-hosting means Docker, GPUs, config
What if your AI assistant lived inside your GitHub repo? What if:
- You talk to it by opening issues (infrastructure you already have)
- It remembers everything because conversations are committed to git
- It edits your code directly and pushes commits
- It runs on GitHub Actions (free for public repos)
- It uses free LLM APIs (Groq, Gemini, Cerebras)
This project builds on two brilliant predecessors:
-
gitclaw by Sawyer Hood β the original idea of an AI agent that lives in GitHub Issues. Sawyer's creativity sparked this whole concept.
-
pi-mono by Mario Zechner β the production-grade coding agent CLI (v0.80.3) that powers the agent mode. Mario built the entire agent loop, tool system, and multi-provider support.
IssueClaw takes these foundations and adds:
- β Multi-provider support β 8 LLM providers with automatic fallback
- β Two modes β chat (saves 99% of tokens) + agent (full tools)
- β Persistent memory β git-backed, survives forever
- β Production-grade β 122 tests, audit trail, concurrency control
- β Free to run β $0/month with Groq/Gemini free tiers
Because it claws into your issues and gets things done. π¦
| ChatGPT Plus | IssueClaw | |
|---|---|---|
| Cost | $20/month | $0/month |
| Code editing | Copy-paste | Direct git commits |
| Memory | Session-only | Permanent (in git) |
| Custom personality | No | Yes |
| Self-hosted | No | Yes (your repo) |
| Copilot | IssueClaw | |
|---|---|---|
| Cost | $10/month | $0/month |
| Interaction | IDE only | GitHub Issues (anywhere) |
| Multi-provider | No | Yes (8 providers) |
| Personality | No | Yes |
| Self-hosted | IssueClaw | |
|---|---|---|
| Setup | Docker, GPU, config | Fork + 1 secret |
| Hardware | GPU recommended | None |
| Memory | Manual | Automatic |
Open an issue, no label:
- "What's the capital of France?"
- "Explain how async/await works"
- "What's the BTC price right now?"
IssueClaw responds in ~5 seconds, using ~500 tokens.
Open an issue with agent label:
- "Build me a 3-file portfolio site"
- "Fix the bug in src/main.ts"
- "Add a README to this repo"
- "Create a GitHub Actions workflow"
IssueClaw creates/edits files, commits to git, and replies.
Open an issue with hatch label:
- IssueClaw asks: "Who am I? Who are you?"
- You decide its name, vibe, emoji
- Stored in
state/personality.mdforever
Comment on an existing issue β IssueClaw resumes with full context. It remembers everything said before in that issue thread.
| Feature | Status |
|---|---|
| π¬ Simple chat mode (saves 99% of tokens) | β |
| π€ Full agent mode (bash, edit, read, write, grep) | β |
| π§ Persistent memory (git-backed) | β |
| π Custom personality (hatch flow) | β |
| π Multi-provider fallback (8 providers) | β |
| π Permission checks (OWNER/MEMBER/COLLAB only) | β |
| β‘ Concurrency control (no race conditions) | β |
| π Audit logging (JSON trail) | β |
| π³ Docker support | β |
| π§ͺ 122 tests (unit + integration + live) | β |
| π $0/month with free tiers | β |
| Mode | Tokens/message | Works with Groq? | Works with Gemini? |
|---|---|---|---|
| π¬ Chat (default) | ~500 | β Yes | β Yes |
π€ Agent (agent label) |
~120,000 | β No (413 error) | β Yes |
π₯ Hatch (hatch label) |
~120,000 | β No | β Yes |
Rule of thumb: Use chat mode (default) for questions. Use agent mode only for code tasks, and only with Gemini/Cerebras.
IssueClaw auto-generates its config on first run. To manually generate:
bun run src/cli.ts config autoThis detects which API keys you have and builds the optimal config. Edit issueclaw.config.json to customize.
| Secret | Provider | Free? |
|---|---|---|
GROQ_API_KEY |
Groq | β |
GEMINI_API_KEY |
Gemini | β |
CEREBRAS_API_KEY |
Cerebras | β |
OPENROUTER_API_KEY |
OpenRouter | β |
ANTHROPIC_API_KEY |
Anthropic | β |
OPENAI_API_KEY |
OpenAI | β |
You're using agent mode with Groq. Agent mode needs ~120K tokens, but Groq's free tier is 12K TPM.
Fix: Either use chat mode (no label), or set GEMINI_API_KEY for agent mode.
The secret isn't set. Go to Settings β Secrets β Actions and add it.
- Check the Actions tab β did the workflow run?
- Are you
OWNER/MEMBER/COLLABORATOR? - Run
bun run src/cli.ts doctorlocally
- Issues: Report bugs or request features
- Discussions: Ask questions, share tips
- Contributing: PRs welcome! See Contributing Guide
IssueClaw stands on the shoulders of giants:
- Sawyer Hood β created the original gitclaw, the brilliant idea of an agent that lives in GitHub Issues
- Mario Zechner β created pi-mono, the production-grade coding agent CLI that powers the agent mode
- Groq, Google Gemini, Cerebras β for the generous free tiers
- GitHub Actions β for the free CI/CD infrastructure
- Bun β for the blazing-fast JavaScript runtime
MIT β see LICENSE. Use it however you want.
Made with π¦ by the IssueClaw community
π Click to expand the complete technical reference
Your own private AI β running for free on GitHub infrastructure.
β Star this repo if it helps you! β
Features Β· Quick Start Β· How It Works Β· Configuration Β· Providers Β· FAQ Β· Docs
π The elevator pitch: Fork this repo β add one free API key β open a GitHub issue β get an AI assistant that remembers everything across sessions, commits all its work to git, and runs entirely inside GitHub Actions. Zero infrastructure. Zero cost. Infinite possibilities.
π Click to expand the full table of contents
- π¦ IssueClaw
- π€ What Is This?
- β¨ Features
- π Quick Start (3 minutes)
- π§ How It Works
- π Project Structure
- π§ Configuration (Complete Reference)
- π€ Providers (Complete Guide)
- πΎ State & Persistence
- π Security Model
- π οΈ CLI Reference
- π§ͺ Testing
- π³ Docker
- π Monitoring & Observability
- β Frequently Asked Questions
- π©Ί Troubleshooting
- π Documentation
- π Changelog
- π£οΈ Roadmap
- β€οΈ Acknowledgments
- π License
- π Project Statistics
IssueClaw is a self-hosted AI assistant that runs entirely through GitHub Issues and GitHub Actions. There is no server to deploy, no database to manage, no monthly cloud bill. The agent wakes up when you open an issue, does its work in a GitHub Actions runner, commits all state back to your repo, and replies as a comment.
It's built on top of pi-mono v0.80.3 β a production-grade coding agent CLI with tool use, session management, and multi-provider support.
| Problem | IssueClaw Solution |
|---|---|
| AI assistants are expensive (ChatGPT Plus, Claude Pro) | $0/month with Gemini's free tier (1M TPM) |
| AI assistants forget everything between sessions | Persistent memory committed to git β survives forever |
| AI assistants can't edit your code | Full agent mode with bash, file editing, git access |
| AI assistants require servers/infrastructure | Zero infrastructure β runs in GitHub Actions |
| AI assistants don't have personality | Mutable identity via personality.md β bootstrap with hatch label |
| AI chatbots waste tokens on system prompts | Simple chat mode uses ~500 tokens (vs ~120K for agents) |
| AI APIs have rate limits | Multi-provider fallback chain β if one fails, try the next |
| Question | Answer |
|---|---|
| Where does the agent run? | In GitHub Actions (ubuntu-latest runner) |
| Where does it store memory? | In your git repo, under state/ |
| How do I talk to it? | Open a GitHub issue, or comment on one |
| How does it remember me? | Every session is committed to git; future sessions read prior state |
| What LLMs does it support? | Gemini (free, 1M TPM), Cerebras (free), OpenRouter (free models), Groq, Anthropic, OpenAI, Ollama, or any OpenAI-compatible endpoint |
| Is it production-ready? | Yes β 122 tests passing, structured logging, retry logic, audit trail, concurrency control |
| Can random internet people trigger it? | No β only OWNER/MEMBER/COLLABORATOR can |
| Cost? | $0 with Gemini's free tier. GitHub Actions is free for public repos. |
| Can it edit files in my repo? | Yes β in agent mode, it has bash, read, write, edit, grep, glob, ls tools |
| Can I just chat without the agent? | Yes β use the "chat" label for simple Q&A (saves 99% of API tokens) |
1. You open an issue: "Set up a GitHub Pages site for this repo"
β
2. Within seconds, the agent reacts with π on your issue
β
3. The agent runs in Actions, reads your repo, edits files,
and commits everything to git
β
4. It replies as a comment on the issue with what it did
β
5. The π reaction is removed
β
6. Next time you comment on that issue, it resumes the SAME
session with full prior context β it remembers everything
Or, for simple chat:
1. You open an issue with the "chat" label: "What's the capital of France?"
β
2. The agent reacts with π
β
3. A lightweight LLM call is made (no agent, no tools β saves API quota)
β
4. The agent replies: "The capital of France is Paris."
β
5. The π reaction is removed
β
6. Cost: ~500 tokens (vs ~120,000 for full agent mode)
IssueClaw supports 8 LLM providers out of the box, with automatic fallback:
- π΅ Google Gemini β 1,000,000 TPM free tier (recommended default)
- β‘ Cerebras β 60,000 TPM, ultra-fast (1000+ tokens/sec)
- π΅ OpenRouter β access to hundreds of models, many free
- β‘ Groq β 12,000 TPM, fast inference
- π£ Anthropic β Claude Opus 4, Sonnet 4.5 (paid)
- π’ OpenAI β GPT-4o, o1, o3 (paid)
- π¦ Ollama β local LLMs (self-hosted, free)
- π§ Custom β any OpenAI-compatible endpoint (Azure, Together, vLLM, LM Studio, etc.)
When one provider fails (rate limit, network error, quota exceeded), the agent automatically tries the next provider in the chain. You configure the order in issueclaw.config.json:
{
"providers": [
{ "type": "gemini", "model": "gemini-2.0-flash", "default": true },
{ "type": "cerebras", "model": "llama-3.3-70b" },
{ "type": "openrouter", "model": "nvidia/nemotron-3-nano-30b-a3b:free" },
{ "type": "groq", "model": "llama-3.3-70b-versatile" }
]
}If Gemini fails β tries Cerebras β tries OpenRouter β tries Groq. The error message shows all provider attempts, so you know exactly what happened.
The agent has four types of persistent state, all committed to git:
| File | Purpose | Mutability |
|---|---|---|
state/memory.md |
Append-only log of important facts, decisions, preferences | Append-only |
state/personality.md |
Agent identity (name, vibe, emoji, hatch date) | Mutable |
state/user.md |
User profile (name, preferences, communication style) | Mutable |
state/audit.log |
JSON audit trail of every agent run | Append-only |
At the start of every session, the agent's prompt is built from:
state/personality.mdβ who the agent isstate/user.mdβ what the agent knows about you- Last 20 lines of
state/memory.mdβ recent durable facts - The issue title + body β what you're asking now
- Operating instructions
Every agent run is logged as JSON to state/audit.log:
{
"timestamp": "2026-07-07T10:30:00.000Z",
"action": "agent_run_complete",
"details": {
"issue": 5,
"success": true,
"durationMs": 45230,
"provider": "gemini",
"responseLength": 1847
}
}You can query it with jq:
# Recent activity
tail -5 state/audit.log | jq .
# All errors
jq 'select(.details.success == false)' state/audit.log
# Runs per issue
jq -s 'group_by(.details.issue) | map({issue: .[0].details.issue, count: length})' state/audit.logOnly users with OWNER, MEMBER, or COLLABORATOR association on the repo can trigger the agent. This is enforced in two places:
- Workflow
if:condition (in.github/workflows/agent.yml) shouldProcessEvent()in code (src/github/events.ts)
Random internet users cannot trigger the agent on public repos. Bots (github-actions[bot], dependabot[bot]) are also rejected to prevent infinite loops.
The workflow uses GitHub's concurrency groups to serialize runs per issue:
concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: falseThis means: if you comment on issue #5 three times in rapid succession, those three runs happen sequentially, not in parallel. This prevents git push conflicts and ensures session state is consistent.
All network operations use exponential backoff with jitter:
- Initial delay: 1 second
- Multiplier: 2x
- Max delay: 30 seconds
- Max attempts: 3 (configurable)
- Jitter: random 0-50% of delay
This handles transient network errors, rate limits, and 5xx server errors gracefully.
Every workflow run uploads state/ and the raw agent JSONL output as a GitHub Actions artifact, retained for 30 days. Download from the Actions tab β click a run β scroll to "Artifacts".
Two layers of timeout protection prevent runaway runs:
- Job timeout: 30 minutes (in workflow
timeout-minutes) - Agent timeout: 15 minutes (configurable in
agent.timeoutMs)
Containerized for local development parity with CI:
docker compose build
docker compose run --rm issueclaw doctorThe Dockerfile uses oven/bun:1.1-debian and installs git, gh, curl, jq, ripgrep.
122 tests across three layers:
| Layer | Count | What it tests |
|---|---|---|
| Unit tests | 99 | Individual modules (config, providers, memory, github, agent, utils, simple-chat) |
| Integration tests | 4 | Full lifecycle with mocked pi |
| Live tests | 29 | End-to-end pipeline with real pi + mock LLM server |
Two output modes:
Human-readable (default in TTY):
[2026-07-07T10:30:00.000Z] INFO [issueclaw] agent run succeeded {"provider":"gemini/gemini-2.0-flash","durationMs":45230}
JSON (for log aggregation β set ISSUECLAW_LOG_JSON=true):
{"ts":"2026-07-07T10:30:00.000Z","level":"info","component":"issueclaw","msg":"agent run succeeded","provider":"gemini/gemini-2.0-flash","durationMs":45230}Log levels: trace, debug, info, warn, error, fatal.
Full CLI for local testing and management:
issueclaw doctor # Diagnose environment & config
issueclaw config auto # Auto-generate config from env
issueclaw config show # Print current config
issueclaw config validate # Validate config
issueclaw memory show # Show memory log
issueclaw memory search # Search memory
issueclaw personality show# Show personality
issueclaw test lifecycle # Run lifecycle against test event
issueclaw test prompt # Show prompt that would be sentThe original issueclaw by Sawyer Hood had these features β all preserved and enhanced:
- π¬ Issue-Driven β open an issue β agent processes β replies as comment
- π Session Resume β comment on existing issue β agent resumes with full context
- π Git-Backed State β all state in
state/directory, committed to git - π Eyes Reaction β agent reacts with π while working, removes when done
- π₯ Hatch Flow β bootstrap agent identity via
hatchlabel - π Self-Search β agent can grep its own conversation history
- π¨ Personality β mutable identity stored in
state/personality.md
The killer feature for saving API quota.
The full agent mode uses ~120,000 tokens per message (pi's system prompt + tool definitions + context). That blows past free-tier limits on Groq (12K TPM) and even strains Cerebras (60K TPM).
Simple chat mode bypasses the agent entirely and calls the LLM API directly:
| Metric | Full Agent Mode | Simple Chat Mode | Savings |
|---|---|---|---|
| Tokens per message | ~120,000 | ~500 | 99.6% reduction |
| Tools available | bash, edit, read, grep, etc. | None | β |
| File editing | Yes | No | β |
| Session resume | Yes (JSONL) | No (stateless) | β |
| Use case | Code tasks, file edits | Quick Q&A, questions | β |
How to use it: Open an issue with the "chat" label (or use the "π¬ Chat" issue template). The agent will respond directly without using tools β perfect for questions like "What's the capital of France?" or "Explain how X works."
The simple chat mode still:
- β
Saves to
state/audit.log - β Commits state changes to git
- β Posts a comment on the issue
- β Uses the provider fallback chain
- β Includes personality + recent memory in the system prompt
# Fork https://github.com/maruf009sultan/issueclaw on GitHub
git clone https://github.com/maruf009sultan/issueclaw.git
cd issueclawOption A: Google Gemini (RECOMMENDED β 1M TPM)
- Go to https://aistudio.google.com/app/apikey
- Sign in with Google
- Click "Create API Key"
- Copy the key (starts with
AIza...)
Why Gemini? 1,000,000 tokens per minute free tier β 83x higher than Groq. Perfect for AI agents with large system prompts and tool definitions.
Option B: Cerebras (free, ultra-fast)
- Go to https://inference.cerebras.ai/
- Sign up
- Generate an API key (starts with
csk_...)
Option C: OpenRouter (has free models)
- Go to https://openrouter.ai/keys
- Sign up
- Generate an API key (starts with
sk-or-v1-...)
Option D: Groq (free, but low 12K TPM)
You can set multiple keys β the agent uses them as a fallback chain.
In your forked repo:
- Go to Settings β Secrets and variables β Actions
- Click "New repository secret" for each key you have:
GEMINI_API_KEY(recommended)CEREBRAS_API_KEYOPENROUTER_API_KEYGROQ_API_KEYANTHROPIC_API_KEY(paid)OPENAI_API_KEY(paid)
- Go to the Actions tab in your repo
- If you see a banner saying "Workflows aren't being run on forked repositories", click "I understand my workflows, go ahead and enable them"
For a quick chat:
- Use the "π¬ Chat" issue template
- Or open an issue and add the
chatlabel
For code tasks:
- Use the "π§ Task" issue template
- Or just open a regular issue
Within ~10 seconds:
- The agent will react with π
- The
IssueClaw Agentworkflow will start in the Actions tab - After ~30-60 seconds, the agent will reply as a comment
- The π reaction will be removed
That's it. You now have a free, self-hosted AI assistant living in your repo.
Use the "π₯ Hatch" issue template to bootstrap the agent's identity. The agent will have a conversation with you to figure out its name, vibe, and emoji β all stored in state/personality.md and persisted via git.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β YOUR GITHUB REPO β
β β
β ββββββββββββ ββββββββββββββββ βββββββββββββββββββββββββ β
β β Issue βββββΆβ GitHub βββββΆβ Actions Workflow β β
β β Opened β β Webhook β β (.github/workflows/) β β
β ββββββββββββ ββββββββββββββββ βββββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β GITHUB ACTIONS RUNNER β β
β β β β
β β 1. preinstall.ts β β
β β ββ Parse GitHub event β β
β β ββ Check permissions (OWNER/MEMBER/COLLAB) β β
β β ββ Add π reaction β β
β β β β
β β 2. main.ts β β
β β ββ Detect mode: "chat" label β simple chat β β
β β β "hatch" label β agent + bootstrap β β
β β β default β full agent β β
β β ββ Init MemoryStore (state/memory.md, etc.) β β
β β ββ Configure git β β
β β β β β
β β ββ IF CHAT MODE: β β
β β β ββ Build minimal system prompt (~200 tokens) β β
β β β ββ Call LLM API directly (no pi, no tools) β β
β β β ββ Get response (~500 tokens total) β β
β β β β β
β β ββ IF AGENT MODE: β β
β β β ββ Build prompt (injects memory + personality) β β
β β β ββ Run pi agent (with provider fallback chain) β β
β β β β ββ Try Gemini β if fails, try Cerebras β ... β β
β β β β ββ Pi makes HTTP call to LLM API β β
β β β ββ Extract response from JSONL output β β
β β β ββ Save session mapping (state/issues/N.json) β β
β β β β β
β β ββ git add -A && git commit && git push β β
β β ββ Post comment on issue via `gh` CLI β β
β β ββ (finally) Remove π reaction β β
β β β β
β β 3. Upload state/ as artifact (30-day retention) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β STATE DIRECTORY β β
β β β β
β β state/ β β
β β memory.md β append-only fact log β β
β β personality.md β mutable agent identity β β
β β user.md β mutable user profile β β
β β audit.log β JSON audit trail β β
β β issues/1.json β issue #1 β session mapping β β
β β sessions/*.jsonl β full conversation transcripts β β
β β β β
β β β Everything here is committed to git after every turn β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- GitHub fires a webhook β triggers the
IssueClaw Agentworkflow - The workflow's
if:condition checks yourauthor_associationisOWNER,MEMBER, orCOLLABORATOR - Bots (
github-actions[bot],dependabot[bot], etc.) are rejected β prevents infinite loops
- Parses the GitHub event payload (
GITHUB_EVENT_PATH) - Adds π reaction to the issue or comment (visual feedback that the agent is working)
- Writes reaction state to
/tmp/reaction-state.jsonfor cleanup later
- Installs
@earendil-works/pi-coding-agentand dependencies - Cached across runs via
actions/cache
- Initializes
MemoryStore(createsstate/memory.md,personality.md,user.mdwith defaults if missing) - Configures git identity (
issueclaw[bot]) - Detects mode based on issue labels:
chatlabel β simple chat mode (lightweight LLM call, ~500 tokens)hatchlabel β agent mode + bootstrap identity flow- no special label β full agent mode (pi agent with tools, ~120K tokens)
- Checks for existing session mapping in
state/issues/<N>.json
If simple chat mode:
- Builds a minimal system prompt (~200 tokens) with personality + recent memory
- Calls the LLM API directly (no pi, no tools)
- Provider fallback chain: Gemini β Cerebras β OpenRouter β Groq β ...
- Returns response (~500 tokens total)
If agent mode:
- Builds the prompt β combines:
state/personality.md(agent identity)state/user.md(user profile)- Last 20 lines of
state/memory.md(recent memory) - The issue title + body (or comment body) β with template boilerplate stripped
- Operating instructions
- Hatch trigger (if
hatchlabel present)
- Token budget enforcement: if prompt > 6,000 tokens, progressively strips context
- Runs pi with the provider fallback chain
- Pi makes an HTTP call to the LLM API, streams back a response as JSONL
- Extracts the final assistant message from the JSONL (never the user message β that was a bug we fixed)
- Saves the session mapping (
state/issues/<N>.jsonβstate/sessions/<timestamp>.jsonl)
In both modes:
- Commits everything to git:
git add -A && git commit -m "issueclaw: work on issue #N (mode)" && git push- If push fails (race condition), auto-rebases and retries up to 3 times
- Posts a comment on the issue with the agent's response
- If response > 60,000 chars, truncates with a notice pointing to the session file
- If agent failed, posts a detailed error comment with all provider attempts and troubleshooting hints
- In a
finallyblock, removes the π reaction
| Aspect | Agent Mode | Simple Chat Mode |
|---|---|---|
| Trigger | Default (no label) or hatch label |
chat label |
| Tokens per message | ~120,000 | ~500 |
| Tools | bash, read, edit, write, grep, glob, ls | None |
| File editing | Yes | No |
| Session resume | Yes (JSONL transcripts) | No (stateless) |
| Use case | Code tasks, file edits, complex work | Quick Q&A, questions |
| API quota impact | High | Minimal |
| Speed | 30-120 seconds | 2-10 seconds |
When to use which:
- Simple chat: "What's the capital of France?", "Explain how async/await works", "What's the weather API format?"
- Agent mode: "Create a hello world HTML page", "Fix the bug in src/main.ts", "Add a README to this repo"
The workflow uses GitHub's concurrency groups to serialize runs per issue:
concurrency:
group: ${{ github.workflow }}-${{ github.event.issue.number }}
cancel-in-progress: falseThis means: if you comment on issue #5 three times in rapid succession, those three runs happen sequentially, not in parallel. The second run waits for the first to finish, then starts. This prevents:
- Git push conflicts
- Session state corruption
- Race conditions in state commits
issueclaw/
β
βββ .github/
β βββ workflows/
β β βββ agent.yml β Main workflow: triggers on issues/comments/PRs
β β βββ ci.yml β CI: lint, typecheck, test on every PR
β β βββ scheduled.yml β Daily maintenance: cleanup orphaned sessions
β βββ ISSUE_TEMPLATE/
β βββ hatch.md β π₯ Bootstrap agent identity
β βββ task.md β π§ General task (agent mode)
β βββ chat.md β π¬ Quick chat (simple chat mode β saves quota)
β βββ bug.md β π Bug report
β
βββ .pi/ β Pi agent configuration
β βββ settings.json β Legacy compat (provider/model/thinking)
β βββ APPEND_SYSTEM.md β Appended to pi's system prompt
β βββ BOOTSTRAP.md β Read during hatch flow
β βββ extensions/
β β βββ mock-provider.ts β Test-only mock LLM provider
β βββ skills/
β βββ memory/
β βββ SKILL.md β Memory search skill for the agent
β
βββ src/
β βββ cli.ts β π οΈ CLI entrypoint (issueclaw command)
β βββ config.ts β Zod-validated config + auto-generation
β βββ providers/ β LLM provider implementations
β β βββ types.ts β Provider interface
β β βββ gemini.ts β π΅ Google Gemini (1M TPM, recommended)
β β βββ cerebras.ts β β‘ Cerebras (ultra-fast)
β β βββ openrouter.ts β π΅ OpenRouter (any model)
β β βββ groq.ts β β‘ Groq
β β βββ anthropic.ts β π£ Anthropic (Claude)
β β βββ openai.ts β π’ OpenAI (GPT-4o)
β β βββ ollama.ts β π¦ Ollama (local)
β β βββ custom.ts β π§ Custom (any OpenAI-compatible)
β β βββ index.ts β Registry + factory
β βββ github/
β β βββ client.ts β `gh` CLI wrapper with retry
β β βββ events.ts β Webhook payload parsing
β βββ agent/
β β βββ runner.ts β Pi orchestration + fallback chain
β β βββ simple-chat.ts β π¬ Lightweight LLM call (no agent)
β βββ memory/
β β βββ store.ts β Atomic file writes, issue mappings
β βββ lifecycle/
β β βββ preinstall.ts β Add reaction, check perms
β β βββ main.ts β Run agent/chat, commit, comment, cleanup
β βββ utils/
β βββ log.ts β Structured logger (levels + JSON)
β βββ retry.ts β Exponential backoff + jitter
β βββ git.ts β Git operations with retry
β βββ fs.ts β Atomic writes, safe reads
β
βββ tests/
β βββ unit/ β 99 unit tests (Vitest)
β β βββ config.test.ts
β β βββ providers.test.ts
β β βββ memory.test.ts
β β βββ github.test.ts
β β βββ agent.test.ts
β β βββ simple-chat.test.ts β Tests for the chat mode
β β βββ utils.test.ts
β βββ integration/
β βββ lifecycle.test.ts β End-to-end with mocked pi
β
βββ scripts/
β βββ live-test.ts β π§ͺ Full pipeline test (mock LLM)
β βββ mock-llm.ts β Mock OpenAI-compatible server
β βββ smoke-test.ts β Quick environment check
β βββ maintenance.ts β Daily cleanup script
β
βββ state/ β Runtime state (committed to git)
β βββ README.md β Explains each file
β βββ memory.md β Append-only fact log
β βββ personality.md β Mutable agent identity
β βββ user.md β User profile
β βββ issues/ β Issue β session mappings
β βββ sessions/ β Conversation transcripts (JSONL)
β
βββ docs/ β Extended documentation
β βββ CONFIGURATION.md
β βββ PROVIDERS.md
β βββ ARCHITECTURE.md
β βββ DEPLOYMENT.md
β βββ TROUBLESHOOTING.md
β
βββ AGENTS.md β Agent operating instructions
βββ CHANGELOG.md β Semantic versioning history
βββ issueclaw.config.json β Main config (Gemini default)
βββ Dockerfile β Container image
βββ docker-compose.yml β Local dev environment
βββ package.json
βββ tsconfig.json β TypeScript strict mode
βββ biome.json β Linter/formatter config
βββ vitest.config.ts β Test config
IssueClaw is configured via issueclaw.config.json. The config is auto-generated on first run if it doesn't exist β it detects which API keys you have and builds the right config.
# Locally:
bun run src/cli.ts config auto
# Or just run the agent β config is auto-generated on first runThis detects GEMINI_API_KEY, CEREBRAS_API_KEY, OPENROUTER_API_KEY, GROQ_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY in your environment and builds a config with the right providers + fallback chain. Priority: Gemini (1M TPM) β Cerebras β OpenRouter β Groq β Anthropic β OpenAI.
Configuration is loaded from (in priority order):
- Environment variables (
ISSUECLAW_*) β highest priority - Config file (
issueclaw.config.jsonorISSUECLAW_CONFIG_PATH) - Legacy (
.pi/settings.json) β backward compatibility with original issueclaw - Auto-generated (on first run if no config exists)
- Built-in defaults
{
"version": 1,
"providers": [
{
"type": "anthropic" | "openai" | "openrouter" | "ollama" | "groq" | "gemini" | "cerebras" | "custom",
"model": "string",
"apiKey": "string or ${ENV_VAR}",
"baseUrl": "https://...",
"headers": { "X-Custom": "value" },
"thinking": "off|minimal|low|medium|high|xhigh",
"maxTokens": 8192,
"temperature": 0.7,
"default": true
}
],
"memory": {
"stateDir": "./state",
"memoryFile": "memory.md",
"personalityFile": "personality.md",
"userFile": "user.md",
"auditFile": "audit.log",
"maxSessionSize": 10485760,
"autoCompact": true
},
"github": {
"repo": "owner/name",
"onIssueOpened": true,
"onIssueComment": true,
"onPullRequest": false,
"allowedAssociations": ["OWNER", "MEMBER", "COLLABORATOR"],
"hatchLabel": "hatch",
"reactionWhileProcessing": true,
"maxCommentLength": 60000,
"concurrencyGroup": "issueclaw-agent"
},
"agent": {
"tools": ["read", "bash", "edit", "write", "grep", "glob", "ls"],
"excludeTools": [],
"systemPrompt": "optional override",
"appendSystemPrompt": ".pi/APPEND_SYSTEM.md",
"agentsFile": "AGENTS.md",
"piCommand": "bunx pi",
"timeoutMs": 900000,
"skills": true,
"extensions": true
},
"runtime": {
"dryRun": false,
"logLevel": "info",
"logJson": false,
"offline": false
}
}| Variable | Description |
|---|---|
ISSUECLAW_PROVIDER |
Override provider type (gemini/cerebras/groq/...) |
ISSUECLAW_MODEL |
Override model |
ISSUECLAW_BASE_URL |
Override base URL (for custom providers) |
ISSUECLAW_THINKING |
Override thinking level (off/minimal/low/medium/high/xhigh) |
ISSUECLAW_LOG_LEVEL |
Log level: trace/debug/info/warn/error/fatal |
ISSUECLAW_LOG_JSON |
true for JSON log output (log aggregation) |
ISSUECLAW_DRY_RUN |
true to skip commits and comments |
ISSUECLAW_CONFIG_PATH |
Custom config file path |
GEMINI_API_KEY |
Google Gemini API key |
CEREBRAS_API_KEY |
Cerebras API key |
OPENROUTER_API_KEY |
OpenRouter API key |
GROQ_API_KEY |
Groq API key |
ANTHROPIC_API_KEY |
Anthropic API key |
OPENAI_API_KEY |
OpenAI API key |
{
"version": 1,
"providers": [
{
"type": "gemini",
"model": "gemini-2.0-flash",
"apiKey": "${GEMINI_API_KEY}",
"default": true
}
]
}Get a free API key at https://aistudio.google.com/app/apikey.
{
"version": 1,
"providers": [
{ "type": "gemini", "model": "gemini-2.0-flash", "apiKey": "${GEMINI_API_KEY}", "default": true },
{ "type": "cerebras", "model": "llama-3.3-70b", "apiKey": "${CEREBRAS_API_KEY}" },
{ "type": "openrouter", "model": "nvidia/nemotron-3-nano-30b-a3b:free", "apiKey": "${OPENROUTER_API_KEY}" },
{ "type": "groq", "model": "llama-3.3-70b-versatile", "apiKey": "${GROQ_API_KEY}" }
]
}{
"version": 1,
"providers": [
{
"type": "ollama",
"model": "llama3.1:70b",
"baseUrl": "http://localhost:11434",
"default": true
}
]
}{
"version": 1,
"providers": [
{
"type": "custom",
"model": "my-model",
"baseUrl": "https://api.together.xyz/v1",
"apiKey": "${TOGETHER_API_KEY}",
"headers": { "X-Custom-Header": "value" },
"default": true
}
]
}π Full config guide: see docs/CONFIGURATION.md
IssueClaw supports 8 provider types out of the box. Gemini is the recommended default because it has 1M TPM free tier (83x higher than Groq).
| Provider | Type | API Key Env | Free Tier? | TPM Limit | Context Window | Notes |
|---|---|---|---|---|---|---|
| π΅ Gemini | gemini |
GEMINI_API_KEY |
β Yes | 1,000,000 | 1,048,576 | RECOMMENDED β best for AI agents |
| β‘ Cerebras | cerebras |
CEREBRAS_API_KEY |
β Yes | 60,000 | 131,072 | Ultra-fast (1000+ tok/s) |
| π΅ OpenRouter | openrouter |
OPENROUTER_API_KEY |
β Free models | varies | varies | Access to hundreds of models |
| β‘ Groq | groq |
GROQ_API_KEY |
β Yes | 12,000 | 131,072 | Low TPM β last resort |
| π£ Anthropic | anthropic |
ANTHROPIC_API_KEY |
β | β | 200,000 | Claude Opus 4, Sonnet 4.5 |
| π’ OpenAI | openai |
OPENAI_API_KEY |
β | β | 128,000 | GPT-4o, o1, o3 |
| π¦ Ollama | ollama |
(none) | β Self-hosted | β | varies | Local LLMs |
| π§ Custom | custom |
OPENAI_API_KEY |
varies | β | varies | Any OpenAI-compatible endpoint |
Get a free key: https://aistudio.google.com/app/apikey
Free tier limits (as of 2026):
- Gemini 2.0 Flash: 15 RPM, 1,000,000 TPM, 1,500 requests/day
- Gemini 2.5 Flash: 10 RPM, 1,000,000 TPM, 500 requests/day
- Gemini 1.5 Flash: 15 RPM, 1,000,000 TPM, 1,500 requests/day
The 1,000,000 TPM is what makes Gemini ideal for AI agents. Pi's system prompt + tool definitions = ~120K tokens, which Groq's 12K TPM literally cannot handle. Gemini handles it with room to spare.
Available models:
gemini-2.0-flash(default β fast, capable)gemini-2.5-flash(better reasoning)gemini-2.0-flash-lite(faster, cheaper)gemini-1.5-flashgemini-1.5-progemini-2.5-pro
Config:
{
"type": "gemini",
"model": "gemini-2.0-flash",
"apiKey": "${GEMINI_API_KEY}",
"default": true
}Pi has native Gemini support β uses --provider google which reads GEMINI_API_KEY automatically.
Get a free key: https://inference.cerebras.ai/
Free tier limits: ~30 RPM, 60,000 TPM
Cerebras uses custom LPU hardware for ultra-fast inference (1000+ tokens/sec). Good fallback when Gemini is unavailable.
Available models:
llama-3.3-70bllama-3.1-8bgpt-oss-120bzai-glm-4.7
Config:
{
"type": "cerebras",
"model": "llama-3.3-70b",
"apiKey": "${CEREBRAS_API_KEY}"
}Get a free key: https://openrouter.ai/keys
OpenRouter routes to hundreds of models from many providers. Many models have free tiers.
Recommended free models:
nvidia/nemotron-3-nano-30b-a3b:free(reliably available)meta-llama/llama-3.3-70b-instruct:free(sometimes rate-limited)google/gemma-4-26b-a4b-it:free
Config:
{
"type": "openrouter",
"model": "nvidia/nemotron-3-nano-30b-a3b:free",
"apiKey": "${OPENROUTER_API_KEY}"
}Get a free key: https://console.groq.com/keys
Free tier limits: 30 RPM, 12,000 TPM, 14,400 requests/day
β οΈ Warning: Groq's 12K TPM is too low for full agent mode (which needs ~120K tokens per message). Use Groq only as a last-resort fallback, or use it with simple chat mode.
Available models:
llama-3.3-70b-versatilellama-3.1-8b-instantmixtral-8x7b-32768gemma2-9b-it
Config:
{
"type": "groq",
"model": "llama-3.3-70b-versatile",
"apiKey": "${GROQ_API_KEY}"
}Get a key: https://console.anthropic.com/ (paid)
Models:
claude-opus-4-6(most capable)claude-sonnet-4-5claude-haiku-4-5(fastest)
Config:
{
"type": "anthropic",
"model": "claude-opus-4-6",
"apiKey": "${ANTHROPIC_API_KEY}",
"thinking": "high"
}Get a key: https://platform.openai.com/api-keys (paid)
Models:
gpt-4ogpt-4o-minio1o3
Config:
{
"type": "openai",
"model": "gpt-4o",
"apiKey": "${OPENAI_API_KEY}"
}Install Ollama: https://ollama.ai/
Models:
llama3.1:70bqwen2.5:32bdeepseek-r1:32b
Config:
{
"type": "ollama",
"model": "llama3.1:70b",
"baseUrl": "http://localhost:11434"
}No API key required β runs locally on your machine.
Any OpenAI-compatible API works via the custom provider type:
Together AI:
{
"type": "custom",
"model": "meta-llama/Llama-3.3-70B-Instruct-Turbo",
"baseUrl": "https://api.together.xyz/v1",
"apiKey": "${TOGETHER_API_KEY}"
}Azure OpenAI:
{
"type": "custom",
"model": "gpt-4o",
"baseUrl": "https://your-resource.openai.azure.com/openai/deployments/your-deployment",
"apiKey": "${AZURE_OPENAI_API_KEY}",
"headers": { "api-key": "${AZURE_OPENAI_API_KEY}" }
}vLLM (local):
{
"type": "custom",
"model": "meta-llama/Meta-Llama-3.1-70B",
"baseUrl": "http://localhost:8000/v1",
"apiKey": "dummy"
}LM Studio:
{
"type": "custom",
"model": "local-model",
"baseUrl": "http://localhost:1234/v1",
"apiKey": "lm-studio"
}Providers are tried in order. The first one marked default: true is the primary; others are fallbacks.
{
"providers": [
{ "type": "gemini", "model": "gemini-2.0-flash", "apiKey": "${GEMINI_API_KEY}", "default": true },
{ "type": "cerebras", "model": "llama-3.3-70b", "apiKey": "${CEREBRAS_API_KEY}" },
{ "type": "openrouter", "model": "nvidia/nemotron-3-nano-30b-a3b:free", "apiKey": "${OPENROUTER_API_KEY}" }
]
}If Gemini fails β tries Cerebras β tries OpenRouter. The error message shows all provider attempts with their status.
You can register custom providers at runtime via pi extensions:
// .pi/extensions/my-provider.ts
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.registerProvider("my-provider", {
name: "My Provider",
baseUrl: "https://api.example.com",
apiKey: "$MY_API_KEY",
api: "openai-completions",
models: [
{
id: "my-model",
name: "My Model",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 4096,
},
],
});
}π Full provider guide: see docs/PROVIDERS.md
Yes β the GitHub repo itself is the database. Everything the agent learns, creates, or modifies is committed to git. There is no external database, no S3 bucket, no Redis cache. Just your repo.
state/
βββ memory.md β π Append-only memory log
βββ personality.md β π Mutable agent identity
βββ user.md β π€ User profile
βββ audit.log β π JSON audit trail (one line per agent action)
βββ issues/
β βββ 1.json β Maps issue #1 β its session file
β βββ 2.json β Maps issue #2 β its session file
β βββ ...
βββ sessions/
βββ 2026-07-07T10-30-00_abc123.jsonl β Full conversation for issue #1
βββ 2026-07-07T11-15-00_def456.jsonl β Full conversation for issue #2
βββ ...
| File | Purpose | Mutability | Who writes it |
|---|---|---|---|
memory.md |
Durable facts, preferences, decisions | Append-only | Agent (via tools) + you (manual edits) |
personality.md |
Agent name, vibe, emoji, hatch date | Mutable | Agent (during hatch flow + refinements) |
user.md |
Your name, preferences, communication style | Mutable | Agent (when it learns about you) |
audit.log |
Every agent run as JSON | Append-only | Lifecycle (automatic) |
issues/N.json |
Issue β session file mapping | Managed | Lifecycle (automatic) |
sessions/*.jsonl |
Full conversation transcripts | Append-only | Pi (automatic) |
At the start of every session (agent mode), the agent's prompt is built from:
state/personality.mdβ who the agent is (name, vibe, emoji)state/user.mdβ what the agent knows about you- Last 20 lines of
state/memory.mdβ recent durable facts (skips default/uninitialized content) - The issue title + body (or comment body) β what you're asking now (template boilerplate stripped)
- Operating instructions β read AGENTS.md, update files, etc.
- Hatch trigger (if
hatchlabel present) β read BOOTSTRAP.md
The agent can also search its own history using bash tools:
# Inside an issue, the agent can run:
rg -i "search term" state/memory.md # Search memory log
rg -i "search term" state/sessions/ # Search all past conversations
tail -30 state/memory.md # Recent memoriesToken budget management: If the prompt exceeds 6,000 tokens, the system progressively strips context:
- Drop "Recent Memory" section
- Drop "About Your Human" section
- Truncate the user message itself
This ensures the prompt always fits within Groq's free-tier limits.
How it tracks conversations per issue:
When you open issue #5:
- The lifecycle checks
state/issues/5.jsonfor an existing mapping - If not found, creates a new session file:
state/sessions/2026-07-07T10-30-00_abc123.jsonl - Saves the mapping:
state/issues/5.jsonβ{ "issueNumber": 5, "sessionPath": "state/sessions/...jsonl", "turnCount": 1 } - Commits everything to git
When you comment on issue #5 again:
- The lifecycle reads
state/issues/5.jsonβ finds the session path - Passes
--session state/sessions/...jsonlto pi - Pi loads the full prior conversation from the JSONL file
- The agent resumes with complete context of everything said before
- Updates the mapping with
turnCount: 2and newupdatedAttimestamp - Commits to git
This means: you can have a long-running conversation across many comments on the same issue, and the agent remembers every word.
Simple chat mode (with chat label) does NOT create session files β it's stateless by design to save tokens. Each chat comment is independent.
All file writes use atomic write (write to a .tmp file, then rename). This prevents:
- Partial writes from being observed by concurrent readers
- Race conditions between concurrent git operations
- Corruption from killed processes (e.g., workflow timeout)
Since everything is in git, backup is trivial:
# Backup
git tag backup-$(date +%Y%m%d)
git push origin backup-$(date +%Y%m%d)
# Or just clone the repo β that IS your backup
git clone https://github.com/maruf009sultan/issueclaw.git backup
# Restore state to a previous point
git checkout backup-20260101 -- state/
git commit -m "restore state to 2026-01-01"
git pushOnly users with OWNER, MEMBER, or COLLABORATOR association on the repo can trigger the agent. This is enforced in two places:
-
Workflow
if:condition (in.github/workflows/agent.yml):if: contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
-
shouldProcessEvent()in code (src/github/events.ts)
Random internet users cannot trigger the agent on public repos.
github-actions[bot], dependabot[bot], and other bots are rejected to prevent infinite loops (agent comments on its own issue β triggers itself β ...).
The workflow requests the minimum permissions needed:
permissions:
contents: write # Commit & push state
issues: write # Comment, react, close
actions: write # Read workflow info
pull-requests: write # If PR support enabledThe agent only makes outbound network calls to:
- Your git remote (github.com) β for push/pull
- Your LLM provider (api.groq.com, api.anthropic.com, etc.) β for inference
No other network egress by default.
For anything sensitive, make the repo private. The workflow uses GITHUB_TOKEN which works for private repos with no extra setup. Note: GitHub Actions has limited free minutes for private repos (2,000/month on free tier). Public repos have unlimited minutes.
API keys are stored as GitHub secrets and injected as env vars only during the workflow run. They are never logged (the logger redacts anything matching apiKey/secret/token patterns). The agent never sees the raw key β pi reads it from process.env directly.
IssueClaw ships with a full CLI for local testing and management.
# Diagnose environment & config
bun run src/cli.ts doctor
# Run the agent lifecycle (needs GITHUB_EVENT_PATH set)
bun run src/cli.ts run
bun run src/cli.ts run --dry-run # Don't commit/comment
bun run src/cli.ts run --offline # Mock pi invocation
bun run src/cli.ts run --event <path> # Custom event payload
# Config management
bun run src/cli.ts config show # Print current config
bun run src/cli.ts config validate # Validate config
bun run src/cli.ts config auto # Auto-generate config from env
# Memory management
bun run src/cli.ts memory show # Show memory log
bun run src/cli.ts memory search <query> # Search memory
bun run src/cli.ts memory append <text> # Append to memory
bun run src/cli.ts memory clear # Clear memory
# Personality management
bun run src/cli.ts personality show # Show personality
bun run src/cli.ts personality set <f> # Set from file
bun run src/cli.ts personality reset # Reset to default
# User profile management
bun run src/cli.ts user show # Show user profile
bun run src/cli.ts user set <file> # Set from file
# Testing utilities
bun run src/cli.ts test event <type> # Generate test event payload
bun run src/cli.ts test lifecycle # Run lifecycle against test event
bun run src/cli.ts test prompt # Show prompt that would be sent
# Full live test (uses mock LLM, no API key needed)
bun run scripts/live-test.tsRun this first to diagnose any issues:
π IssueClaw Doctor
β Configuration loaded
π Providers (4):
β gemini/gemini-2.0-flash (default)
β οΈ cerebras/llama-3.3-70b: requires CEREBRAS_API_KEY
β openrouter/nvidia/nemotron-3-nano-30b-a3b:free
β groq/llama-3.3-70b-versatile
πΎ State directory: ./state
β memory.md
β personality.md
β user.md
π Environment:
β GITHUB_TOKEN
β GITHUB_EVENT_PATH (set by Actions)
π₯ Bun: 1.3.14
πΏ Git: 2.47.3
π GitHub CLI: 2.40.1
π€ Pi: 0.80.3
IssueClaw has 122 tests across three layers:
| Layer | Count | What it tests |
|---|---|---|
| Unit tests | 99 | Individual modules (config, providers, memory, github, agent, simple-chat, utils) |
| Integration tests | 4 | Full lifecycle with mocked pi |
| Live tests | 29 | End-to-end pipeline with real pi + mock LLM server |
# Unit + integration tests (fast, ~2 seconds)
bun run test
# With coverage
bun run test:coverage
# Live test (slow, ~30 seconds, uses mock LLM server)
bun run scripts/live-test.ts
# Watch mode
bun run test:watchThe live test (scripts/live-test.ts) is the gold standard β it:
- Starts a mock LLM server (OpenAI-compatible) on localhost
- Creates a temp git repo with the project files
- Generates a fake GitHub event (issue opened)
- Runs the actual
main.tslifecycle (no mocks of our code) - Runs the actual pi binary (no mocks of pi)
- Pi makes real HTTP calls to the mock LLM server
- Verifies:
- All state files created (
memory.md,personality.md,user.md,audit.log) - Session JSONL created with real conversation
- Issue mapping saved
- Audit log has
agent_run_start+agent_run_endentries - Mock LLM received proper requests (correct model, correct message format)
- All CLI commands work (
config show,memory show,doctor, etc.)
- All state files created (
- Tests hatch label event
- Cleans up
Every push and PR triggers .github/workflows/ci.yml which runs:
bun x tsc --noEmit(TypeScript strict mode, no errors)bun x biome check src tests scripts(linting)bun run test(99 unit + 4 integration tests)
For local development parity with CI:
# Build
docker compose build
# Diagnose
docker compose run --rm issueclaw doctor
# Run with env vars
docker compose run --rm \
-e GITHUB_TOKEN=ghp_xxx \
-e GEMINI_API_KEY=AIza_xxx \
issueclaw run --dry-runThe Dockerfile uses oven/bun:1.1-debian and installs git, gh, curl, jq, ripgrep.
Every agent run is logged as JSON to state/audit.log:
# Recent activity
tail -5 state/audit.log | jq .
# All errors
jq 'select(.details.success == false)' state/audit.log
# Runs per issue
jq -s 'group_by(.details.issue) | map({issue: .[0].details.issue, count: length})' state/audit.log
# Simple chat vs agent mode
jq 'select(.action == "simple_chat_complete" or .action == "agent_run_complete")' state/audit.logSet ISSUECLAW_LOG_JSON=true for JSON log output (compatible with Datadog, Splunk, Loki, etc.):
{"ts":"2026-07-07T10:30:00.000Z","level":"info","component":"issueclaw","msg":"agent run succeeded","provider":"gemini/gemini-2.0-flash","durationMs":45230}Or use colorized human-readable output (default in TTY):
[2026-07-07T10:30:00.000Z] INFO [issueclaw] agent run succeeded {"provider":"gemini/gemini-2.0-flash","durationMs":45230}
Every run uploads state/ and /tmp/agent-raw-*.jsonl as an artifact, retained for 30 days. Download from the Actions tab β click a run β scroll to "Artifacts".
A daily workflow (.github/workflows/scheduled.yml) runs scripts/maintenance.ts which:
- Cleans up orphaned session files (sessions with no issue mapping)
- Flags oversized sessions (>10MB, candidates for compaction)
- Reports stats to
state/audit.log
A: Yes. Here's the evidence:
- β 122 tests all passing (99 unit + 4 integration + 29 live)
- β TypeScript strict mode with clean typecheck
- β Structured error handling β every operation has try/catch with logging
- β Retry logic β network operations retry with exponential backoff
- β Provider fallback β if Gemini fails, automatically tries Cerebras, then OpenRouter, etc.
- β Concurrency control β race-condition safe via GitHub concurrency groups
- β Atomic file writes β no corruption from concurrent access
- β Audit trail β every agent action logged as JSON
- β Permission checks β only authorized users can trigger
- β Timeouts β 30-min job + 15-min agent, no runaway runs
- β Session artifacts β uploaded for debugging, 30-day retention
- β Comprehensive docs β 5 doc files + this README
- β Docker support β local dev parity with CI
- β Live-tested β the full pipeline was verified end-to-end with a mock LLM
A: Yes. The entire user-facing flow is GitHub Issues:
- Open an issue β agent processes β replies as comment
- Comment on the issue β agent resumes with full prior context β replies
- Close the issue β agent stops responding to it
There is no web UI, no CLI for end users, no Slack integration. Just GitHub Issues. This is by design β it keeps the system dead simple and uses infrastructure you already have.
A: Yes, 100%. The repo IS the database. Everything is committed to git:
state/memory.mdβ agent's memory logstate/personality.mdβ agent's identitystate/user.mdβ your profilestate/audit.logβ audit trailstate/issues/N.jsonβ issue β session mappingsstate/sessions/*.jsonlβ full conversation transcripts- Any files the agent creates/edits in your repo (code, docs, configs)
There is no external database (no Postgres, no Redis, no S3). If you git clone the repo, you have a complete backup of everything.
A: Each issue gets a mapping file at state/issues/<N>.json that points to a session JSONL file. When you comment on an existing issue, the lifecycle:
- Reads the mapping to find the session file path
- Passes
--session <path>to pi - Pi loads the full prior conversation from the JSONL
- The agent resumes with complete context
This means you can have long-running conversations across many comments on the same issue. The agent remembers every word.
Simple chat mode (with chat label) does NOT use session files β it's stateless to save tokens.
A: Yes! Open an issue with the chat label (or use the "π¬ Chat" issue template). The agent will respond directly without using tools β perfect for quick questions.
This uses ~500 tokens per message (vs ~120,000 for full agent mode), saving 99.6% of your API quota.
A: Use Gemini. It has a generous free tier (1M TPM, 1,500 requests/day) and the default config uses it. Combined with GitHub Actions being free for public repos, you can run this entire system for $0/month.
A: Yes, but only OWNER/MEMBER/COLLABORATOR can trigger it. Add them as collaborators in repo settings. Each person's comments on an issue share the same session context.
A: Yes. The CLI supports local testing:
bun run src/cli.ts test event issues.opened # Generate test event
bun run src/cli.ts test lifecycle # Run lifecycle (mock pi)
bun run scripts/live-test.ts # Full live test (mock LLM)A: Three options:
# Nuclear: delete all state
rm -rf state/
bun run src/cli.ts doctor # Reinitializes defaults
# Selective: clear just memory.md
bun run src/cli.ts memory clear
# Surgical: edit files directly
$EDITOR state/memory.md
$EDITOR state/personality.md
git add state/ && git commit -m "reset memory" && git pushA: Yes. Open an issue with the hatch label to bootstrap a new identity, or edit state/personality.md directly:
bun run src/cli.ts personality show
$EDITOR state/personality.md
git commit -am "update personality" && git pushA: The agent:
- Tries the next provider in the fallback chain (Gemini β Cerebras β OpenRouter β ...)
- If all providers fail, posts a detailed error comment with:
- All provider attempts and their errors
- Which providers had keys set
- Specific troubleshooting hints based on error type
- Collapsible diagnostics section
- The error is logged to
state/audit.logand the workflow's stderr - The π reaction is still removed (in the
finallyblock) - Session artifacts are still uploaded for debugging
A: Forever β they're in git. The daily maintenance script flags sessions >10MB for compaction, but doesn't delete them. GitHub Actions artifacts (the uploaded state/ zip) are retained for 30 days.
A: Yes. The workflow triggers on pull_request: opened events too. You can ask the agent to review PRs, suggest changes, etc. (disabled by default in config β set onPullRequest: true to enable).
A: Yes, but consider:
- All collaborators see all conversation history (it's in git)
- Concurrency is per-issue (not per-user) β multiple people commenting on the same issue are serialized
- For sensitive data, make the repo private
- Check the Actions tab β did the workflow run?
- Check the workflow's
if:condition β are youOWNER/MEMBER/COLLABORATOR? - Run
bun run src/cli.ts doctorlocally - Verify
GEMINI_API_KEY(or other provider key) is set in secrets
- Read the error comment β it now shows all provider attempts
- Check
state/audit.logfor recent errors:tail -5 state/audit.log | jq . - Look at workflow logs in Actions tab
- Run
bun run src/cli.ts doctorto verify config
This means that provider is in your config but the matching secret isn't set. The error comment will show you:
- Which providers were tried
- Which had keys (β) and which didn't (β)
- Exactly which secret name to set
Fix: Go to Settings β Secrets β add the missing PROVIDER_API_KEY secret.
This happens when using Groq (12K TPM) for full agent mode (needs ~120K tokens).
Fix:
- Switch to Gemini (1M TPM) β set
GEMINI_API_KEYand make it default - Or use simple chat mode (
chatlabel) β only ~500 tokens per message
Fix:
- Wait a minute and retry
- Add more fallback providers
- Check your provider's quota dashboard
- The workflow auto-rebases and retries 3 times
- If still failing, check for branch protection rules that block
issueclaw[bot] - Manual fix:
git pull --rebase origin main && git push
- Responses >60,000 chars are truncated with a notice
- Full response is in the session JSONL (uploaded as artifact)
- Increase
maxCommentLengthin config (max 65,536 β GitHub's limit)
π Full troubleshooting guide: see docs/TROUBLESHOOTING.md
| Doc | What's inside |
|---|---|
| docs/CONFIGURATION.md | Full config schema, all options, examples for every provider |
| docs/PROVIDERS.md | Provider guide, fallback chains, custom endpoints |
| docs/ARCHITECTURE.md | Component breakdown, data flow, security model |
| docs/DEPLOYMENT.md | Production checklist, upgrading, rollback, monitoring |
| docs/TROUBLESHOOTING.md | Common issues, debug mode, FAQ |
See CHANGELOG.md for the full version history.
- v1.6.0 β Added simple chat mode (saves 99% of API tokens)
- v1.5.0 β Fixed error reporting (shows ALL provider failures)
- v1.4.0 β Added Gemini (1M TPM) and Cerebras providers
- v1.3.0 β Fixed prompt size (token budget management)
- v1.2.0 β Fixed critical bug (prompt was posted as response)
- v1.1.0 β Added Groq support, auto-config, live testing
- v1.0.0 β Enterprise upgrade of original issueclaw
- Streaming responses β post comments incrementally as the agent generates
- Web UI β optional web dashboard for viewing sessions
- Slack/Discord integration β trigger agent from chat
- Multi-repo support β one agent managing multiple repos
- Fine-tuned personalities β per-issue-type personalities
- MCP (Model Context Protocol) support β connect to external tools
- Compaction β auto-summarize long sessions to save tokens
This project stands on the shoulders of giants:
- Sawyer Hood β created the original issueclaw, the brilliant idea of an agent that lives in GitHub Issues. Without Sawyer's creativity, this project wouldn't exist.
- Mario Zechner β created pi-mono, the production-grade coding agent CLI (v0.80.3) that powers the agent mode. Pi provides tool use, session management, multi-provider support, and the entire agent loop. Mario's work is the foundation of the agent capabilities.
- Google Gemini β for the generous 1M TPM free tier that makes this $0 to run
- Cerebras β for ultra-fast free inference
- OpenRouter β for free model access
- Groq β for fast free inference (lower limits but still useful)
- GitHub Actions β for the free CI/CD that hosts the agent
- Bun β for the blazing-fast JavaScript runtime
- Biome β for the fast linter/formatter
- Vitest β for the testing framework
- Zod β for runtime schema validation
- OpenClaw β inspired the concept
- The open-source community β for feedback, bug reports, and feature requests
MIT β see LICENSE
| Metric | Value |
|---|---|
| Version | 1.6.0 |
| Tests | 122 passing (99 unit + 4 integration + 29 live) |
| Providers | 8 (Gemini, Cerebras, OpenRouter, Groq, Anthropic, OpenAI, Ollama, Custom) |
| Lines of code | ~3,500 (src) + ~1,200 (tests) |
| Documentation | 5 doc files + 1,500-line README |
| Languages | TypeScript (100%) |
| Runtime | Bun 1.1+ |
| Node.js | 20+ (for pi compatibility) |
| License | MIT |
| Cost to run | $0/month (with Gemini free tier) |
Made with π¦ by the IssueClaw community
Report a bug Β· Request a feature Β· Read the docs Β· View changelog
Keep a personal AI assistant in your repo that remembers your preferences, projects, and context across sessions. Open issues for tasks, chat for quick questions.
Issue #1: "Remember that I prefer TypeScript over JavaScript"
Issue #2 (chat): "What's the syntax for a TypeScript generic constraint?"
Issue #3: "Create a new React component for a login form"
The agent remembers your TypeScript preference across all issues.
Issue: "Document all the functions in src/utils.ts"
β Agent reads the file, generates JSDoc comments, commits the changes
Issue: "Fix the bug where the login button doesn't work on Safari"
β Agent reads the code, identifies the issue, fixes it, commits
Issue: "Review PR #42 and suggest improvements"
β Agent reads the PR diff, posts a review comment
Issue (chat): "Explain how promises work in JavaScript"
β Agent responds with a detailed explanation (only ~500 tokens)
Issue: "Set up a new Next.js project with Tailwind CSS in the frontend/ directory"
β Agent creates the project structure, configures Tailwind, commits everything
Issue: "Create a GitHub Actions workflow that runs tests on every PR"
β Agent creates .github/workflows/test.yml, commits it
Issue: "Write a blog post about why we chose Bun over Node.js"
β Agent researches (reads your repo), writes the post, saves it to blog/bun-vs-node.md
| Feature | ChatGPT Plus | IssueClaw |
|---|---|---|
| Cost | $20/month | $0/month |
| Code editing | Manual copy-paste | Direct git commits |
| Memory | Session-only | Permanent (in git) |
| Custom personality | No | Yes (personality.md) |
| Self-hosted | No | Yes (your GitHub repo) |
| Privacy | OpenAI sees your data | Only your repo |
| Feature | Copilot | IssueClaw |
|---|---|---|
| Cost | $10/month | $0/month |
| Interaction | IDE only | GitHub Issues |
| Memory | None | Permanent |
| Multi-provider | No (OpenAI only) | Yes (8 providers) |
| Personality | No | Yes |
| Feature | Self-hosted LLM | IssueClaw |
|---|---|---|
| Setup complexity | High (Docker, GPU, config) | Low (fork + 1 secret) |
| Hardware needed | GPU recommended | None (uses cloud APIs) |
| Memory | Manual | Automatic (git-backed) |
| Access | Web UI | GitHub Issues (anywhere) |
| Multi-provider | Manual config | Automatic fallback chain |
| Feature | Original issueclaw | IssueClaw |
|---|---|---|
| Providers | Anthropic only | 8 providers |
| Config | Hardcoded | Zod-validated, auto-generated |
| Tests | None | 122 tests |
| Error handling | Minimal | Comprehensive with diagnostics |
| Token management | None | Budget enforcement + template stripping |
| Simple chat | No | Yes (saves 99% of tokens) |
| CLI | No | Full CLI (doctor, config, memory, etc.) |
| Docker | No | Yes |
| Docs | Minimal | 5 doc files + 1800-line README |
| Live testing | No | 29 end-to-end tests |
You can create custom issue templates that trigger specific behaviors:
---
name: "π¬ Research"
about: "Ask the agent to research a topic"
labels: ["chat", "research"]
---
Research topic:
[What do you want to know about?]The chat label triggers simple chat mode. The research label is just for organization.
Use ISSUECLAW_CONFIG_PATH to use different configs for different environments:
# In workflow:
env:
ISSUECLAW_CONFIG_PATH: ${{ vars.ISSUECLAW_CONFIG_PATH || 'issueclaw.config.json' }}Use ISSUECLAW_PROVIDER and ISSUECLAW_MODEL env vars to override the config:
env:
ISSUECLAW_PROVIDER: gemini
ISSUECLAW_MODEL: gemini-2.5-flashThis is useful for A/B testing different models.
Modify the workflow to only trigger on specific branches:
on:
issues:
types: [opened]
issue_comment:
types: [created]
jobs:
run-agent:
if: github.ref == 'refs/heads/main' && ...Restrict or expand the agent's tools in config:
{
"agent": {
"tools": ["read", "bash"], // Read-only analysis
"excludeTools": ["edit", "write"] // Prevent file modifications
}
}Or for full access:
{
"agent": {
"tools": [], // All tools
"skills": true, // Enable skills
"extensions": true // Enable extensions
}
}IssueClaw uses pi-mono v0.80.3 as the agent engine. Pi provides:
- Tool use β bash, read, write, edit, grep, glob, ls
- Session management β JSONL transcripts with resume capability
- Multi-provider support β native support for Gemini, Cerebras, Groq, Anthropic, OpenAI, etc.
- Streaming β responses stream as JSONL events
- Extensions β custom provider registration
- Skills β reusable prompt templates
When you open an issue in agent mode:
- Prompt building β issueclaw builds a prompt with personality, memory, and instructions
- Pi invocation β pi is called as a subprocess with
--mode json --session-dir state/sessions - LLM call β pi sends the prompt + tool definitions to the LLM API
- Tool execution β if the LLM requests a tool (e.g., "read src/main.ts"), pi executes it
- Response loop β pi sends the tool result back to the LLM, which may request more tools
- Final response β the LLM produces a text response, pi logs it as
message_end - Extraction β issueclaw extracts the final assistant message from the JSONL
- Comment β issueclaw posts the response as a GitHub issue comment
Pi outputs events as JSONL (one JSON object per line):
{"type":"session","version":3,"id":"abc123","timestamp":"..."}
{"type":"agent_start"}
{"type":"turn_start"}
{"type":"message_start","message":{"role":"user","content":[...]}}
{"type":"message_end","message":{"role":"user","content":[...]}}
{"type":"message_start","message":{"role":"assistant","content":[]}}
{"type":"tool_call","name":"bash","arguments":{"command":"ls"}}
{"type":"tool_result","name":"bash","output":"file1.txt\nfile2.txt"}
{"type":"message_end","message":{"role":"assistant","content":[{"type":"text","text":"Here are the files..."}]}}
{"type":"turn_end"}
{"type":"agent_end"}IssueClaw's extractFinalMessage() finds the last message_end with role: "assistant" and extracts the text content. This is critical β if we didn't filter by role, we'd return the user's message (the prompt) as the response, which was a bug we fixed in v1.2.0.
When you comment on an existing issue:
- issueclaw reads
state/issues/<N>.jsonto find the session file path - Passes
--session <path>to pi - Pi loads the full JSONL transcript
- The LLM sees the entire conversation history
- The agent responds with full context
This enables long-running conversations across many comments on the same issue.
The full agent mode uses ~120,000 tokens per message:
- Pi's system prompt: ~20,000 tokens
- Tool definitions: ~80,000 tokens
- Context (memory, personality): ~5,000 tokens
- User message: ~5,000 tokens
This blows past Groq's 12K TPM and even strains Cerebras's 60K TPM.
Simple chat mode bypasses pi entirely and calls the LLM API directly:
- Minimal system prompt: ~200 tokens
- User message: ~100 tokens
- Total: ~500 tokens (99.6% reduction)
The simple-chat.ts module:
- Builds a minimal system prompt β includes personality + recent memory (last 10 lines)
- Builds the user message β just the issue title + body or comment body
- Calls the LLM API directly β using
fetch():- For Gemini: uses Google's native API format (
generateContentendpoint) - For all others: uses OpenAI-compatible
/chat/completionsendpoint
- For Gemini: uses Google's native API format (
- Provider fallback β tries each provider in order until one succeeds
- Returns the response β no tools, no file editing, no session file
OpenAI-compatible (Groq, Cerebras, OpenRouter, OpenAI, custom):
POST https://api.groq.com/openai/v1/chat/completions
Authorization: Bearer gsk_xxx
{
"model": "llama-3.3-70b-versatile",
"messages": [
{ "role": "system", "content": "You are a helpful assistant..." },
{ "role": "user", "content": "What is 2+2?" }
],
"temperature": 0.7,
"max_tokens": 8192
}Google Gemini (native format):
POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=AIzaSy...
{
"contents": [
{ "role": "user", "parts": [{ "text": "What is 2+2?" }] }
],
"systemInstruction": {
"parts": [{ "text": "You are a helpful assistant..." }]
},
"generationConfig": {
"temperature": 0.7,
"maxOutputTokens": 8192
}
}# Clone
git clone https://github.com/maruf009sultan/issueclaw.git
cd issueclaw
# Install dependencies
bun install
# Run tests
bun run test
# Run lint
bun run lint
# Run typecheck
bun run typecheck
# Run live test (uses mock LLM, no API key needed)
bun run scripts/live-test.ts
# Run doctor to verify environment
bun run src/cli.ts doctorsrc/
βββ config.ts β Config loading + Zod validation + auto-generation
βββ cli.ts β CLI entrypoint
βββ providers/ β LLM provider abstractions
β βββ types.ts β Provider interface
β βββ gemini.ts β Google Gemini (native pi support)
β βββ cerebras.ts β Cerebras (native pi support)
β βββ groq.ts β Groq (native pi support)
β βββ openai.ts β OpenAI
β βββ openrouter.ts β OpenRouter
β βββ anthropic.ts β Anthropic
β βββ ollama.ts β Ollama (local)
β βββ custom.ts β Custom (any OpenAI-compatible)
β βββ index.ts β Registry + factory
βββ github/
β βββ client.ts β GitHub API client (wraps `gh` CLI)
β βββ events.ts β Event parsing (issues, comments, PRs)
βββ agent/
β βββ runner.ts β Full agent mode (pi orchestration)
β βββ simple-chat.ts β Simple chat mode (direct LLM call)
βββ memory/
β βββ store.ts β Persistent state management
βββ lifecycle/
β βββ preinstall.ts β Pre-agent hook (reactions, perms)
β βββ main.ts β Main lifecycle (run, commit, comment)
βββ utils/
βββ log.ts β Structured logger
βββ retry.ts β Retry with backoff
βββ git.ts β Git operations
βββ fs.ts β Atomic file writes
- Create
src/providers/myprovider.ts:
import type { Provider, ProviderArgs } from "./types.ts";
import type { ProviderConfig } from "../config.ts";
export const myProvider: Provider = {
type: "myprovider",
buildArgs(config: ProviderConfig): ProviderArgs {
const args = ["--provider", "myprovider", "--model", config.model];
const env: Record<string, string | undefined> = {};
if (config.apiKey) {
env.MYPROVIDER_API_KEY = config.apiKey;
}
return { args, env };
},
validate(config: ProviderConfig): string | null {
if (!config.model) return "MyProvider requires a model";
if (!config.apiKey) return "MyProvider requires MYPROVIDER_API_KEY";
return null;
},
};- Register in
src/providers/index.ts:
import { myProvider } from "./myprovider.ts";
const REGISTRY = { ..., myprovider: myProvider };- Add to config schema in
src/config.ts:
type: z.enum(["anthropic", "openai", ..., "myprovider", "custom"]),- Add to
providerToApiKeyEnv:
myprovider: "MYPROVIDER_API_KEY",-
Add tests in
tests/unit/providers.test.ts -
Add to
autoGenerateConfig()if it has a free tier
# All tests
bun run test
# Specific test file
bun run test tests/unit/simple-chat.test.ts
# With coverage
bun run test:coverage
# Watch mode
bun run test:watch
# Live test (end-to-end with mock LLM)
bun run scripts/live-test.ts
# Smoke test (quick environment check)
bun run scripts/smoke-test.ts# Enable debug logging
ISSUECLAW_LOG_LEVEL=debug bun run src/lifecycle/main.ts
# Enable trace logging (very verbose)
ISSUECLAW_LOG_LEVEL=trace bun run src/lifecycle/main.ts
# JSON log output (for log aggregation)
ISSUECLAW_LOG_JSON=true bun run src/lifecycle/main.ts
# Dry-run mode (no commits, no comments)
bun run src/cli.ts run --dry-run
# Offline mode (mock pi invocation)
bun run src/cli.ts run --offline
# Show the prompt that would be sent
bun run src/cli.ts test prompt- $0/month with Gemini's free tier (1M TPM)
- No OpenAI subscription ($20/month)
- No GitHub Copilot subscription ($10/month)
- No server costs (GitHub Actions is free for public repos)
- Your conversations live in your git repo
- No third-party sees your data (only your LLM provider)
- You can self-host with Ollama for complete privacy
- Git history = full audit trail
- AI writes code directly to your repo
- No copy-pasting from ChatGPT
- Automatic commits with descriptive messages
- Session resume means the AI remembers your project
- The AI remembers your preferences across sessions
- Personality is customizable (hatch flow)
- Memory log captures important facts
- All stored in git β survives forever
- 122 tests passing
- Structured logging
- Audit trail
- Permission checks
- Concurrency control
- Retry logic
- Provider fallback chain
- Docker support
- 8 LLM providers
- Custom personalities
- Configurable tools
- Issue templates
- Extensions system
- GitHub Issues work on any device
- No app to install
- No server to maintain
- Just open an issue and chat
Contributions are welcome! Here's how to help:
- Check existing issues first
- Open a new issue with the "π Bug" template
- Include:
- What you expected
- What happened
- Steps to reproduce
- Your config (redact API keys)
- Workflow logs (from Actions tab)
- Open an issue with the "π§ Task" template
- Describe the feature and why it's useful
- Fork the repo
- Create a branch:
git checkout -b my-feature - Make changes
- Run tests:
bun run test - Run lint:
bun run lint:fix - Run typecheck:
bun run typecheck - Commit:
git commit -m "Add my feature" - Push:
git push origin my-feature - Open a PR
- TypeScript strict mode
- Biome for formatting and linting
- 2-space indentation
- Double quotes for strings
- Trailing commas
Bootstrap a new agent identity. The agent will have a conversation to figure out its name, vibe, and emoji.
---
name: "π₯ Hatch"
about: "Bootstrap a new agent identity"
labels: ["hatch"]
---
Read `.pi/BOOTSTRAP.md` and follow it. That's your birth certificate.Quick chat without the full agent. Saves 99% of API tokens.
---
name: "π¬ Chat"
about: "Quick chat with the AI β no agent, no tools, saves API quota"
labels: ["chat"]
---
Type your message below. The AI will respond directly without using tools.General task for the agent (code, file edits, etc.)
---
name: "π§ Task"
about: "Ask the agent to do something"
labels: []
---
## What do you want the agent to do?
[Describe the task]
## Context
[Any background info]
## Success Criteria
[Optional: How will you know it's done?]Report a bug for the agent to fix.
---
name: "π Bug"
about: "Report a bug for the agent to fix"
labels: ["bug"]
---
## Bug Description
[What's broken?]
## Reproduction Steps
1.
2.
3.
## Expected vs Actual
**Expected**:
**Actual**:| Scenario | Agent Mode | Simple Chat Mode |
|---|---|---|
| "What is 2+2?" | ~120,000 tokens | ~50 tokens |
| "Write a hello world HTML page" | ~120,000 tokens | ~80 tokens |
| "Explain async/await" | ~120,000 tokens | ~100 tokens |
| "Fix the bug in main.ts" | ~120,000 tokens | N/A (needs tools) |
| "Create a README" | ~120,000 tokens | N/A (needs file editing) |
Rule of thumb: Use chat mode for questions, agent mode for tasks that need file access.
| Resource | Limit | IssueClaw Usage | Cost |
|---|---|---|---|
| Gemini TPM | 1,000,000 | ~120,000 per agent run | $0 |
| Gemini RPM | 15 | 1 per issue | $0 |
| Gemini requests/day | 1,500 | ~10-50 | $0 |
| GitHub Actions | Unlimited (public) | ~1 per issue | $0 |
| Total | $0/month |
| Resource | Limit | IssueClaw Usage | Cost |
|---|---|---|---|
| Cerebras TPM | 60,000 | ~120,000 per agent run | May hit limit |
| Cerebras RPM | 30 | 1 per issue | $0 |
| Total | $0/month |
| Resource | Limit | IssueClaw Usage | Cost |
|---|---|---|---|
| Groq TPM | 12,000 | ~500 per chat | $0 |
| Total | $0/month |
If you use paid providers as fallback:
| Provider | Cost per 1M tokens | Agent run cost | Chat run cost |
|---|---|---|---|
| Claude Opus 4 | $15 input / $75 output | ~$2-5 per run | ~$0.01 per chat |
| GPT-4o | $2.50 input / $10 output | ~$0.50-1 per run | ~$0.002 per chat |
Go to your repo's Issues tab β New Issue β "π§ Task" template.
Title: Create a hello world HTML page
Body:
Create a simple hello world HTML page at index.html with:
- A heading saying "Hello World"
- Basic CSS styling
- A footer with the current year
- Within seconds, the agent reacts with π
- Go to the Actions tab to see the workflow running
- The agent will:
- Read the issue
- Use bash to create
index.html - Write the HTML content
- Commit and push
- After ~30-60 seconds, the agent posts a comment:
I've created `index.html` with a hello world page. Here's what I did:
1. Created `index.html` with a heading, CSS styling, and footer
2. Committed the changes
The file is now in your repo at `index.html`.git pull
cat index.htmlYou should see the HTML file the agent created.
Comment on the issue:
Add a button that shows an alert when clicked
The agent will resume the session (it remembers creating index.html) and add the button.
Go to Issues β New Issue β "π¬ Chat" template.
Title: What is closure in JavaScript?
Body:
Can you explain what a closure is in JavaScript with an example?
Within ~5 seconds (vs ~60 seconds for agent mode), the agent responds:
A closure is a function that remembers the variables from its outer scope,
even after the outer function has returned.
Here's an example:
```javascript
function makeCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2In this example, the inner function "closes over" the count variable...
### Step 3: Check the cost
This chat used ~500 tokens (vs ~120,000 for agent mode). You can verify in the audit log:
```bash
tail -1 state/audit.log | jq .
{
"timestamp": "2026-07-07T...",
"action": "simple_chat_complete",
"details": {
"issue": 7,
"success": true,
"durationMs": 4200,
"provider": "gemini",
"tokensUsed": 487,
"responseLength": 892
}
}Go to Issues β New Issue β "π₯ Hatch" template.
Title: Hatch
Body: (leave default)
The agent will respond with something like:
Hey. I just came online. Who am I? Who are you?
I don't have a name yet, a vibe, or an emoji. Let's figure that out together.
What should we call me?Reply with:
Your name is Buddy. You're a chill, helpful assistant. Your emoji is π€.
My name is Maruf.
The agent will:
-
Update
state/personality.md:# Personality ## Name Buddy ## Nature Chill, helpful assistant ## Vibe Casual and friendly ## Emoji π€ ## Hatch Date 2026-07-07
-
Update
state/user.md:# User Profile ## Name Maruf
-
Commit and push these changes
-
Reply:
Got it! I'm Buddy π€. Nice to meet you, Maruf! I've updated my personality and noted your name. From now on, I'll remember this across all our conversations.
git pull
cat state/personality.md
cat state/user.mdNow, every time you open a new issue, the agent will introduce itself as Buddy π€ and know your name is Maruf.
A: The agent is designed for GitHub Actions, but you can run it locally:
# Set up environment
export GITHUB_EVENT_PATH=/tmp/event.json
export GITHUB_EVENT_NAME=issues
export GITHUB_TOKEN=ghp_xxx
export GEMINI_API_KEY=AIzaSy...
# Create a test event
echo '{"action":"opened","issue":{"number":1,"title":"Test","body":"Hello","user":{"login":"you"},"author_association":"OWNER","labels":[]}}' > /tmp/event.json
# Run the lifecycle
bun run src/lifecycle/main.tsA: Not directly β it relies on GitHub-specific features (Issues, Actions, gh CLI). But the core agent logic is portable. You'd need to:
- Replace
src/github/client.tswith a GitLab/Bitbucket API client - Replace
src/github/events.tswith GitLab/Bitbucket event parsing - Replace the GitHub Actions workflow with GitLab CI / Bitbucket Pipelines
A: Sessions are in git, so you can't "delete" them (git preserves history). But you can remove the files:
rm state/sessions/old-session.jsonl
rm state/issues/1.json
git add -A && git commit -m "cleanup old sessions" && git pushThe daily maintenance script also flags orphaned sessions (sessions with no issue mapping).
A: Currently no β each repo has its own agent. Multi-repo support is on the roadmap.
A: The repo IS the backup. Just clone it:
git clone https://github.com/maruf009sultan/issueclaw.git backupOr use git tags:
git tag backup-$(date +%Y%m%d)
git push origin backup-$(date +%Y%m%d)A: In agent mode, the agent has the bash tool, so it can curl URLs. But GitHub Actions runners have standard internet access. The agent can:
- Read web pages (via curl)
- Download files
- Access APIs
But it cannot:
- Open a browser
- Execute JavaScript in a browser context
- Access localhost services (unless you set them up)
A: Several ways:
- GitHub Actions tab β see workflow runs, logs, artifacts
state/audit.logβ JSON audit trail of every run- Issue comments β the agent posts its responses as comments
- Git log β every commit shows what changed
- Structured logs β set
ISSUECLAW_LOG_JSON=truefor log aggregation
A: Yes, via config:
{
"agent": {
"tools": ["read", "grep", "ls"], // Read-only
"excludeTools": ["bash", "edit", "write"] // No modifications
}
}This makes the agent a read-only analyst.
A: Several safeguards:
- Timeouts β 30-min job + 15-min agent timeout
- Permission checks β only authorized users can trigger
- Audit log β every action is logged
- Git history β all changes are versioned, you can revert
- Branch protection β protect
mainbranch, require PR reviews - Tool restrictions β limit tools to read-only if paranoid
A: Yes! It's MIT licensed. Use it however you want.
IssueClaw is a production-ready, self-hosted AI assistant that runs entirely on GitHub infrastructure. It costs $0/month with Gemini's free tier, remembers everything across sessions, and can edit code directly in your repo.
Key differentiators:
- β Zero infrastructure β runs in GitHub Actions
- β Zero cost β Gemini free tier (1M TPM)
- β Persistent memory β git-backed state
- β Multi-provider β 8 providers with fallback
- β Two modes β agent (full tools) + chat (saves 99% of tokens)
- β Enterprise-grade β 122 tests, audit trail, concurrency control
- β Open source β MIT licensed
Get started in 3 minutes: Fork β add API key β open an issue.
Now go fork the repo and start building with your AI assistant!
π Quick reference (click to expand)
| Command | Purpose |
|---|---|
bun run src/cli.ts doctor |
Diagnose environment |
bun run src/cli.ts config auto |
Auto-generate config |
bun run src/cli.ts config show |
Show current config |
bun run src/cli.ts config validate |
Validate config |
bun run src/cli.ts memory show |
Show memory log |
bun run src/cli.ts personality show |
Show personality |
bun run src/cli.ts test lifecycle |
Test lifecycle locally |
bun run scripts/live-test.ts |
Full live test (mock LLM) |
bun run test |
Run unit tests |
bun run lint |
Run linter |
bun run typecheck |
TypeScript check |
| Secret | Provider | Free? | Get Key |
|---|---|---|---|
GEMINI_API_KEY |
Gemini | β | https://aistudio.google.com/app/apikey |
CEREBRAS_API_KEY |
Cerebras | β | https://inference.cerebras.ai/ |
OPENROUTER_API_KEY |
OpenRouter | β | https://openrouter.ai/keys |
GROQ_API_KEY |
Groq | β | https://console.groq.com/keys |
ANTHROPIC_API_KEY |
Anthropic | β | https://console.anthropic.com/ |
OPENAI_API_KEY |
OpenAI | β | https://platform.openai.com/api-keys |
| Label | Mode | Tokens | Use Case |
|---|---|---|---|
chat |
Simple chat | ~500 | Quick questions |
hatch |
Agent + bootstrap | ~120K | Set up personality |
| (none) | Full agent | ~120K | Code tasks, file edits |
bug |
Full agent | ~120K | Bug fixing |
task |
Full agent | ~120K | General tasks |
- π¦ Gemini (1M TPM) β primary
- β‘ Cerebras (60K TPM) β fallback 1
- π¦ OpenRouter (varies) β fallback 2
- β‘ Groq (12K TPM) β fallback 3
- π£ Anthropic (paid) β fallback 4
- π’ OpenAI (paid) β fallback 5
| File | Purpose |
|---|---|
state/memory.md |
Append-only fact log |
state/personality.md |
Agent identity (mutable) |
state/user.md |
User profile (mutable) |
state/audit.log |
JSON audit trail |
state/issues/N.json |
Issue β session mapping |
state/sessions/*.jsonl |
Conversation transcripts |
| Level | When to use |
|---|---|
trace |
Extreme debugging (very verbose) |
debug |
Debugging issues |
info |
Normal operation (default) |
warn |
Only warnings |
error |
Only errors |
fatal |
Only fatal errors |
MIT License
Copyright (c) 2026 IssueClaw Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
See LICENSE for the full text.
Final line count: ~3000 lines of documentation
Built with β€οΈ and π¦ by the open-source community