logo
0
0
WeChat Login
Parshva Daftari<89991302+parshvadaftari@users.noreply.github.com>
Scaffold gitclaw agent (#16)

GitClaw Logo

npm version node version license typescript

Gitclaw

A universal git-native multimodal always learning AI Agent (TinyHuman)
Your agent lives inside a git repo — identity, rules, memory, tools, and skills are all version-controlled files.

InstallQuick StartSDKArchitectureToolsHooksSkillsPlugins


Why Gitclaw?

Most agent frameworks treat configuration as code scattered across your application. Gitclaw flips this — your agent IS a git repository:

  • agent.yaml — model, tools, runtime config
  • SOUL.md — personality and identity
  • RULES.md — behavioral constraints
  • memory/ — git-committed memory with full history
  • tools/ — declarative YAML tool definitions
  • skills/ — composable skill modules
  • hooks/ — lifecycle hooks (script or programmatic)

Fork an agent. Branch a personality. git log your agent's memory. Diff its rules. This is agents as repos.

One-Command Install

Copy, paste, run. That's it — no cloning, no manual setup. The installer handles everything:

bash <(curl -fsSL "https://raw.githubusercontent.com/open-gitagent/gitclaw/main/install.sh?$(date +%s)")

This will:

  • Install gitclaw globally via npm
  • Walk you through API key setup (Quick or Advanced mode)
  • Launch the voice UI in your browser at http://localhost:3333

Requirements: Node.js 18+, npm, git

Or install manually:

npm install -g gitclaw

Quick Start

Run your first agent in one line:

export OPENAI_API_KEY="sk-..." gitclaw --dir ~/my-project "Explain this project and suggest improvements"

That's it. Gitclaw auto-scaffolds everything on first run — agent.yaml, SOUL.md, memory/ — and drops you into the agent.

Local Repo Mode

Clone a GitHub repo, run an agent on it, auto-commit and push to a session branch:

gitclaw --repo https://github.com/org/repo --pat ghp_xxx "Fix the login bug"

Resume an existing session:

gitclaw --repo https://github.com/org/repo --pat ghp_xxx --session gitclaw/session-a1b2c3d4 "Continue"

Token can come from env instead of --pat:

export GITHUB_TOKEN=ghp_xxx gitclaw --repo https://github.com/org/repo "Add unit tests"

CLI Options

FlagShortDescription
--dir <path>-dAgent directory (default: cwd)
--repo <url>-rGitHub repo URL to clone and work on
--pat <token>GitHub PAT (or set GITHUB_TOKEN / GIT_TOKEN)
--session <branch>Resume an existing session branch
--model <provider:model>-mOverride model (e.g. anthropic:claude-sonnet-4-5-20250929)
--sandbox-sRun in sandbox VM
--prompt <text>-pSingle-shot prompt (skip REPL)
--env <name>-eEnvironment config

SDK

npm install gitclaw
import { query } from "gitclaw"; // Simple query for await (const msg of query({ prompt: "List all TypeScript files and summarize them", dir: "./my-agent", model: "openai:gpt-4o-mini", })) { if (msg.type === "delta") process.stdout.write(msg.content); if (msg.type === "assistant") console.log("\n\nDone."); } // Local repo mode via SDK for await (const msg of query({ prompt: "Fix the login bug", model: "openai:gpt-4o-mini", repo: { url: "https://github.com/org/repo", token: process.env.GITHUB_TOKEN!, }, })) { if (msg.type === "delta") process.stdout.write(msg.content); }

SDK

The SDK provides a programmatic interface to Gitclaw agents. It mirrors the Claude Agent SDK pattern but runs in-process — no subprocesses, no IPC.

query(options): Query

Returns an AsyncGenerator<GCMessage> that streams agent events.

import { query } from "gitclaw"; for await (const msg of query({ prompt: "Refactor the auth module", dir: "/path/to/agent", model: "anthropic:claude-sonnet-4-5-20250929", })) { switch (msg.type) { case "delta": // streaming text chunk process.stdout.write(msg.content); break; case "assistant": // complete response console.log(`\nTokens: ${msg.usage?.totalTokens}`); break; case "tool_use": // tool invocation console.log(`Tool: ${msg.toolName}(${JSON.stringify(msg.args)})`); break; case "tool_result": // tool output console.log(`Result: ${msg.content}`); break; case "system": // lifecycle events & errors console.log(`[${msg.subtype}] ${msg.content}`); break; } }

tool(name, description, schema, handler): GCToolDefinition

Define custom tools the agent can call:

import { query, tool } from "gitclaw"; const search = tool( "search_docs", "Search the documentation", { properties: { query: { type: "string", description: "Search query" }, limit: { type: "number", description: "Max results" }, }, required: ["query"], }, async (args) => { const results = await mySearchEngine(args.query, args.limit ?? 10); return { text: JSON.stringify(results), details: { count: results.length } }; }, ); for await (const msg of query({ prompt: "Find docs about authentication", tools: [search], })) { // agent can now call search_docs }

Hooks

Programmatic lifecycle hooks for gating, logging, and control:

for await (const msg of query({ prompt: "Deploy the service", hooks: { preToolUse: async (ctx) => { // Block dangerous operations if (ctx.toolName === "cli" && ctx.args.command?.includes("rm -rf")) return { action: "block", reason: "Destructive command blocked" }; // Modify arguments if (ctx.toolName === "write" && !ctx.args.path.startsWith("/safe/")) return { action: "modify", args: { ...ctx.args, path: `/safe/${ctx.args.path}` } }; return { action: "allow" }; }, onError: async (ctx) => { console.error(`Agent error: ${ctx.error}`); }, }, })) { // ... }

QueryOptions Reference

OptionTypeDescription
promptstring | AsyncIterableUser prompt or multi-turn stream
dirstringAgent directory (default: cwd)
modelstring"provider:model-id"
envstringEnvironment config (config/<env>.yaml)
systemPromptstringOverride discovered system prompt
systemPromptSuffixstringAppend to discovered system prompt
toolsGCToolDefinition[]Additional tools
replaceBuiltinToolsbooleanSkip cli/read/write/memory
allowedToolsstring[]Tool name allowlist
disallowedToolsstring[]Tool name denylist
repoLocalRepoOptionsClone a GitHub repo and work on a session branch
sandboxSandboxOptions | booleanRun in sandbox VM (mutually exclusive with repo)
hooksGCHooksProgrammatic lifecycle hooks
maxTurnsnumberMax agent turns
abortControllerAbortControllerCancellation signal
constraintsobjecttemperature, maxTokens, topP, topK

Message Types

TypeDescriptionKey Fields
deltaStreaming text/thinking chunkdeltaType, content
assistantComplete LLM responsecontent, model, usage, stopReason
tool_useTool invocationtoolName, args, toolCallId
tool_resultTool outputcontent, isError, toolCallId
systemLifecycle eventssubtype, content, metadata
userUser message (multi-turn)content

Architecture

my-agent/ ├── agent.yaml # Model, tools, runtime config ├── SOUL.md # Agent identity & personality ├── RULES.md # Behavioral rules & constraints ├── DUTIES.md # Role-specific responsibilities ├── memory/ │ └── MEMORY.md # Git-committed agent memory ├── tools/ │ └── *.yaml # Declarative tool definitions ├── skills/ │ └── <name>/ │ ├── SKILL.md # Skill instructions (YAML frontmatter) │ └── scripts/ # Skill scripts ├── workflows/ │ └── *.yaml|*.md # Multi-step workflow definitions ├── agents/ │ └── <name>/ # Sub-agent definitions ├── plugins/ │ └── <name>/ # Local plugins (plugin.yaml + tools/hooks/skills) ├── hooks/ │ └── hooks.yaml # Lifecycle hook scripts ├── knowledge/ │ └── index.yaml # Knowledge base entries ├── config/ │ ├── default.yaml # Default environment config │ └── <env>.yaml # Environment overrides ├── examples/ │ └── *.md # Few-shot examples └── compliance/ └── *.yaml # Compliance & audit config

Agent Manifest (agent.yaml)

spec_version: "0.1.0" name: my-agent version: 1.0.0 description: An agent that does things model: preferred: "anthropic:claude-sonnet-4-5-20250929" fallback: ["openai:gpt-4o"] constraints: temperature: 0.7 max_tokens: 4096 tools: [cli, read, write, memory] runtime: max_turns: 50 timeout: 120 # Optional extends: "https://github.com/org/base-agent.git" skills: [code-review, deploy] delegation: mode: auto compliance: risk_level: medium human_in_the_loop: true

Tools

Built-in Tools

ToolDescription
cliExecute shell commands
readRead files with pagination
writeWrite/create files
memoryLoad/save git-committed memory

Declarative Tools

Define tools as YAML in tools/:

# tools/search.yaml name: search description: Search the codebase input_schema: properties: query: type: string description: Search query path: type: string description: Directory to search required: [query] implementation: script: search.sh runtime: sh

The script receives args as JSON on stdin and returns output on stdout.

Hooks

Script-based hooks in hooks/hooks.yaml:

hooks: on_session_start: - script: validate-env.sh description: Check environment is ready pre_tool_use: - script: audit-tools.sh description: Log and gate tool usage post_response: - script: notify.sh on_error: - script: alert.sh

Hook scripts receive context as JSON on stdin and return:

{ "action": "allow" } { "action": "block", "reason": "Not permitted" } { "action": "modify", "args": { "modified": "args" } }

Skills

Skills are composable instruction modules in skills/<name>/:

skills/ code-review/ SKILL.md scripts/ lint.sh
--- name: code-review description: Review code for quality and security --- # Code Review When reviewing code: 1. Check for security vulnerabilities 2. Verify error handling 3. Run the lint script for style checks

Invoke via CLI: /skill:code-review Review the auth module

Plugins

Plugins are reusable extensions that can provide tools, hooks, skills, prompts, and memory layers. They follow the same git-native philosophy — a plugin is a directory with a plugin.yaml manifest.

CLI Commands

# Install from git URL gitclaw plugin install https://github.com/org/my-plugin.git # Install from local path gitclaw plugin install ./path/to/plugin # Install with options gitclaw plugin install <source> --name custom-name --force --no-enable # List all discovered plugins gitclaw plugin list # Enable / disable gitclaw plugin enable my-plugin gitclaw plugin disable my-plugin # Remove gitclaw plugin remove my-plugin # Scaffold a new plugin gitclaw plugin init my-plugin
FlagDescription
--name <name>Custom plugin name (default: derived from source)
--forceReinstall even if already present
--no-enableInstall without auto-enabling

Plugin Manifest (plugin.yaml)

id: my-plugin # Required, kebab-case name: My Plugin version: 0.1.0 description: What this plugin does author: Your Name license: MIT engine: ">=0.3.0" # Min gitclaw version provides: tools: true # Load tools from tools/*.yaml skills: true # Load skills from skills/ prompt: prompt.md # Inject into system prompt hooks: pre_tool_use: - script: hooks/audit.sh description: Audit tool calls config: properties: api_key: type: string description: API key env: MY_API_KEY # Env var fallback timeout: type: number default: 30 required: [api_key] entry: index.ts # Optional programmatic entry point

Plugin Config in agent.yaml

plugins: my-plugin: enabled: true source: https://github.com/org/my-plugin.git # Auto-install on load version: main # Git branch/tag config: api_key: "${MY_API_KEY}" # Supports env interpolation timeout: 60

Config resolution priority: agent.yaml config > env var > manifest default.

Discovery Order

Plugins are discovered in this order (first match wins):

  1. Local<agent-dir>/plugins/<name>/
  2. Global~/.gitclaw/plugins/<name>/
  3. Installed<agent-dir>/.gitagent/plugins/<name>/

Programmatic Plugins

Plugins with an entry field in their manifest get a full API:

// index.ts import type { GitclawPluginApi } from "gitclaw"; export async function register(api: GitclawPluginApi) { // Register a tool api.registerTool({ name: "search_docs", description: "Search documentation", inputSchema: { properties: { query: { type: "string" } }, required: ["query"], }, handler: async (args) => { const results = await search(args.query); return { text: JSON.stringify(results) }; }, }); // Register a lifecycle hook api.registerHook("pre_tool_use", async (ctx) => { api.logger.info(`Tool called: ${ctx.tool}`); return { action: "allow" }; }); // Add to system prompt api.addPrompt("Always check docs before answering questions."); // Register a memory layer api.registerMemoryLayer({ name: "docs-cache", path: "memory/docs-cache.md", description: "Cached documentation lookups", }); }

Available API methods:

MethodDescription
registerTool(def)Register a tool the agent can call
registerHook(event, handler)Register a lifecycle hook (on_session_start, pre_tool_use, post_response, on_error)
addPrompt(text)Append text to the system prompt
registerMemoryLayer(layer)Register a memory layer
logger.info/warn/error(msg)Prefixed logging ([plugin:id])
pluginIdPlugin identifier
pluginDirAbsolute path to plugin directory
configResolved config values

Plugin Structure

my-plugin/ ├── plugin.yaml # Manifest (required) ├── tools/ # Declarative tool definitions │ └── *.yaml ├── hooks/ # Hook scripts ├── skills/ # Skill modules ├── prompt.md # System prompt addition └── index.ts # Programmatic entry point

Multi-Model Support

Gitclaw works with any LLM provider supported by pi-ai:

# agent.yaml model: preferred: "anthropic:claude-sonnet-4-5-20250929" fallback: - "openai:gpt-4o" - "google:gemini-2.0-flash"

Supported providers: anthropic, openai, google, xai, groq, mistral, and more.

Inheritance & Composition

Agents can extend base agents:

# agent.yaml extends: "https://github.com/org/base-agent.git" # Dependencies dependencies: - name: shared-tools source: "https://github.com/org/shared-tools.git" version: main mount: tools # Sub-agents delegation: mode: auto

Compliance & Audit

Built-in compliance validation and audit logging:

# agent.yaml compliance: risk_level: high human_in_the_loop: true data_classification: confidential regulatory_frameworks: [SOC2, GDPR] recordkeeping: audit_logging: true retention_days: 90

Audit logs are written to .gitagent/audit.jsonl with full tool invocation traces.

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

This project is licensed under the MIT License.