# planck-claw

Headless, OpenRouter-only AI agent library. A minimal, API-first agent engine for building autonomous AI agents in TypeScript/Node.js.

## Features

- **Agent Loop** -- LLM-driven agent that iterates between reasoning and tool execution
- **OpenRouter Provider** -- Single-provider design, access all models through OpenRouter
- **Tool Registry** -- Extensible `BaseTool` pattern for custom tool implementations
- **Skills System** -- Load markdown files as context injected into the system prompt
- **Internal Messaging** -- MessageBus + BaseChannel for agent-to-agent communication
- **Cron Scheduling** -- Persistent cron job management with node-cron
- **Session Management** -- File-based session persistence
- **Heartbeat** -- Periodic wake-up mechanism for proactive tasks
- **Headless** -- No CLI, no UI. Pure library API.

## Installation

```bash
npm install planck-claw
```

## Quick Start

```typescript
import { AgentLoop, ProviderManager } from 'planck-claw';

const config = {
  providers: {
    openrouter: { apiKey: process.env.OPENROUTER_API_KEY },
  },
  agents: {
    defaults: { model: 'anthropic/claude-sonnet-4' },
  },
};

const agent = new AgentLoop('session-1', config);
const response = await agent.processMessage('Hello, what can you do?');
console.log(response.content);
```

## Custom Tools

Extend the agent with custom tools by implementing `BaseTool`:

```typescript
import { BaseTool, ToolRegistry } from 'planck-claw';

class WeatherTool extends BaseTool {
  name = 'get_weather';
  description = 'Get current weather for a location';

  getDefinition() {
    return {
      type: 'function' as const,
      function: {
        name: this.name,
        description: this.description,
        parameters: {
          type: 'object',
          properties: {
            location: { type: 'string', description: 'City name' },
          },
          required: ['location'],
        },
      },
    };
  }

  async execute(args: Record<string, unknown>) {
    const location = args.location as string;
    return this.success(`Weather in ${location}: 72°F, sunny`);
  }
}
```

## Agent-to-Agent Communication

Use the MessageBus for inter-agent messaging:

```typescript
import { getMessageBus } from 'planck-claw';

const bus = getMessageBus();

bus.subscribeAll(async (message) => {
  console.log(`Message from ${message.channelType}: ${message.content}`);
});

await bus.publish({
  id: 'msg-1',
  sessionId: 'session-1',
  userId: 'agent-a',
  content: 'Hello from Agent A',
  channelType: 'internal',
  timestamp: new Date(),
});
```

## Configuration

planck-claw uses a simple config object:

```typescript
const config = {
  providers: {
    openrouter: {
      apiKey: 'sk-or-...',
      apiBase: 'https://openrouter.ai/api/v1', // optional
    },
  },
  agents: {
    defaults: {
      model: 'anthropic/claude-sonnet-4',
      temperature: 0.7,
      maxTokens: 4096,
      systemPrompt: 'You are a helpful assistant.',
    },
  },
  tools: {
    restrictToWorkspace: false,
    allowedCommands: [],
    deniedCommands: [],
  },
};
```

## API Reference

### Core

- `AgentLoop` -- Main agent loop (LLM + tool execution)
- `Memory` -- Conversation memory (JSON-based)
- `ContextBuilder` -- System prompt assembly
- `SkillsLoader` -- Markdown skills loader
- `Subagent` -- Background task execution

### Tools

- `ToolRegistry` -- Tool registration and execution
- `BaseTool` -- Abstract base class for custom tools
- `ShellTool` -- Built-in shell command execution
- `ReadFileTool` / `WriteFileTool` -- Built-in file I/O

### Provider

- `ProviderManager` -- OpenRouter provider manager
- `OpenRouterProvider` -- Direct OpenRouter API client

### Messaging

- `MessageBus` -- Pub/sub event routing
- `BaseChannel` -- Abstract channel for custom integrations
- `ChannelManager` -- Channel lifecycle management
- `GatewayServer` -- Message routing orchestrator

### Scheduling

- `CronManager` -- Persistent cron job management
- `CronScheduler` -- Runtime cron scheduling

## License

MIT
