Metadata-Version: 2.4
Name: agent-forge-installer
Version: 0.2.8
Summary: AgentForge — multi-agent Telegram bot framework powered by Claude Code
Author: Martin Rancourt
License: MIT
Project-URL: Homepage, https://github.com/Martin-Rancourt/agentforge
Project-URL: Repository, https://github.com/Martin-Rancourt/agentforge
Project-URL: Bug Tracker, https://github.com/Martin-Rancourt/agentforge/issues
Keywords: telegram,bot,ai,claude,multi-agent,framework
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: fastapi<1,>=0.116
Requires-Dist: pydantic<3,>=2.0
Requires-Dist: uvicorn<1,>=0.35
Provides-Extra: http
Requires-Dist: requests>=2.28; extra == "http"
Provides-Extra: voice
Requires-Dist: faster-whisper>=1.0; extra == "voice"
Provides-Extra: embeddings
Requires-Dist: sentence-transformers>=2.0; extra == "embeddings"
Requires-Dist: numpy>=1.24; extra == "embeddings"
Provides-Extra: google
Requires-Dist: google-api-python-client>=2.100; extra == "google"
Requires-Dist: google-auth>=2.20; extra == "google"
Provides-Extra: full
Requires-Dist: requests>=2.28; extra == "full"
Requires-Dist: faster-whisper>=1.0; extra == "full"
Requires-Dist: sentence-transformers>=2.0; extra == "full"
Requires-Dist: numpy>=1.24; extra == "full"
Requires-Dist: google-api-python-client>=2.100; extra == "full"
Requires-Dist: google-auth>=2.20; extra == "full"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Requires-Dist: httpx>=0.28; extra == "dev"

# AgentForge

A reusable framework for building multi-agent Telegram bots powered by Claude AI.

**Zero dependencies** by default — runs on Python 3.10+ stdlib. Optional extras for voice transcription and faster HTTP.

## Native App Scaffold

This repo now includes an Apple-platform scaffold under `apps/` for future native clients:

- `AgentForgeKit` shared Swift module for models, networking stubs, and utilities
- `AgentForgeiOS` SwiftUI app target for iOS 17+
- `AgentForgemacOS` SwiftUI app target for macOS 14+

Build commands:

```bash
make native-build      # Builds the shared Swift package
make native-test       # Runs the shared Swift package tests
make ios-build         # Builds the iOS app target with xcodebuild
make macos-build       # Builds the macOS app target with xcodebuild
make native-verify     # Runs all of the above
```

Open the native project in Xcode with `open apps/AgentForgeApps.xcodeproj`.

Important: this native app currently uses both the Swift package manifest at `apps/Package.swift` and the Xcode project at `apps/AgentForgeApps.xcodeproj`. When adding, renaming, or removing Swift source files for the native app, update `apps/AgentForgeApps.xcodeproj/project.pbxproj` as well or Xcode may show "Cannot find ... in scope" errors even if `swift build` succeeds.

## Quick Start

```bash
# Clone and install
git clone https://github.com/Martin-Rancourt/AgentForge.git
cd AgentForge
./install.sh

# Configure
agentforge init              # Launch interactive setup wizard

# Create agents
agentforge agent create assistant --model sonnet --thread-id 11
agentforge agent create researcher --model opus --thread-id 12

# Run
agentforge bot
```

## How It Works

AgentForge turns a **Telegram Supergroup with Forum Topics** into a multi-agent workspace. Each topic routes to a different Claude-powered agent with its own identity, model, and memory.

```
Telegram Topic (thread_id: 12)
  → telegram_adapter.py (long-polling)
  → message_router.py (resolve agent config)
  → claude_runner.py (invoke Claude CLI with agent's soul.md)
  → Response sent back to Telegram
```

### Message Flow

1. Bot polls Telegram for new messages
2. `message_thread_id` determines which agent handles the message
3. Conversation history is loaded from SQLite (configurable context window)
4. Claude Code CLI is invoked with the agent's `soul.md` as system prompt
5. Response is stored in SQLite and sent back to Telegram

## Architecture

```
agentforge/
├── src/agentforge/
│   ├── telegram_adapter.py   # Main bot — polling, routing, sending
│   ├── claude_runner.py      # Claude Code CLI subprocess wrapper
│   ├── message_router.py     # Thread → agent config resolution
│   ├── config.py             # Typed config loader (dataclasses)
│   ├── memory_manager.py     # SQLite + FTS5 conversation database
│   ├── vault.py              # Structured memory store (per-agent)
│   ├── voice.py              # Voice note transcription (optional)
│   ├── http_client.py        # Dual-stack: requests or urllib
│   └── cli/                  # CLI commands (bot, agent, memory, init, vault)
├── scripts/                   # Bash utilities
│   ├── telegram_send.sh      # Send messages to topics (with dedup)
│   ├── heartbeat.sh          # Proactive task runner (cron)
│   ├── healthcheck.sh        # Daily system health check
│   ├── agent_task.sh         # Cross-agent task delegation
│   ├── log_action.sh         # Action logging (Google Sheets + local)
│   └── memory_consolidation.sh  # Weekly memory merge
├── tests/                     # Pytest suite (49 tests)
├── install.sh                # One-liner bootstrap
└── pyproject.toml            # Package metadata
```

## CLI Reference

### `agentforge bot`

Start the Telegram bot.

```bash
agentforge bot [--config path/to/config.json]
```

### `agentforge agent`

Manage agents declaratively.

```bash
# Create — scaffolds soul.md, memory.md, daily/ directory
agentforge agent create <name> --model <model> --thread-id <id>

# List all configured agents
agentforge agent list

# Remove an agent (--keep-files to preserve files on disk)
agentforge agent remove <name> [--keep-files]
```

**Models:** `sonnet` (fast, balanced), `opus` (strongest reasoning), `haiku` (fastest, cheapest)

### `agentforge memory`

Query the conversation database.

```bash
agentforge memory search "deployment error"    # Full-text search (FTS5)
agentforge memory recent 50                     # Last 50 messages
agentforge memory stats                         # Database statistics
```

### `agentforge vault`

Structured memory store — facts, preferences, and knowledge per agent.

```bash
agentforge vault write --agent victor --category knowledge --title "API design" --content "..."
agentforge vault search "deployment"
agentforge vault list --agent archie
```

### `agentforge init`

Bootstrap a new instance from scratch.

```bash
agentforge init [--dir /path/to/instance]
agentforge init --non-interactive [--dir /path/to/instance]
```

Default behavior launches an interactive wizard that validates the Telegram token, detects a chat ID after `/start`, checks Claude Code CLI readiness, captures bot identity, and writes `.env`, `bot/config.json`, and `memory/soul.md`.

Use `--non-interactive` to preserve the original scaffold-only flow.

The interactive wizard also checks `gh auth status` and prints a non-blocking warning if GitHub auth is missing. Use either `gh auth login` or set `GH_TOKEN` in `.env` before running GitHub-driven automation.

## Configuration

### `bot/config.json`

```jsonc
{
  "telegram": {
    "token_env_var": "AGENTFORGE_TELEGRAM_TOKEN",  // env var name holding the token
    "bot_username": "agentforge_bot",               // optional expected bot username
    "allowed_chat_ids": [123456789],                // whitelist
    "group_chat_id": -100123456789,                 // supergroup ID
    "topics": {                                      // named topic shortcuts
      "general": 11,
      "dev": 12
    }
  },
  "claude": {
    "model": "sonnet",          // default model
    "max_budget_usd": 1.0       // per-invocation spend cap
  },
  "memory": {
    "context_messages": 10      // messages included as context
  },
  "threads": {
    "11": { "name": "assistant", "model": "sonnet", "context_messages": 10 },
    "12": { "name": "researcher", "model": "opus",  "context_messages": 15 }
  }
}
```

### `.env`

```bash
AGENTFORGE_TELEGRAM_TOKEN=your_bot_token_here
AGENTFORGE_ROOT=/path/to/instance    # defaults to /home/clawdia
# Optional: preferred GitHub auth token for gh/API usage
GH_TOKEN=ghp_xxx
# Compatibility only; prefer GH_TOKEN above
GITHUB_TOKEN=ghp_xxx
# Optional: preserve gh credential lookup when HOME is overridden
GH_CONFIG_DIR=/Users/you/.config/gh
```

When AgentForge invokes Claude CLI, it sets `HOME` to `AGENTFORGE_ROOT`. Setting `GH_CONFIG_DIR` (or letting AgentForge infer it from your original home directory) keeps `gh` credential resolution stable in that environment.

## Multi-Agent System

Each agent gets its own identity via a `soul.md` file:

```
agents/
├── victor/
│   ├── soul.md        # Personality, role, instructions
│   ├── memory.md      # Long-term consolidated memory
│   └── daily/         # Daily learnings (YYYY-MM-DD.md)
├── archie/
└── catherine/
```

The `soul.md` is passed as `--system-prompt` to Claude, completely overriding the default identity. Agents can:

- Have different Claude models (opus for complex reasoning, haiku for quick tasks)
- Maintain separate conversation histories and context windows
- Store per-agent structured memory in the vault
- Delegate tasks to each other via `agent_task.sh`

### Project Topics

Beyond agent topics, you can configure **project topics** where multiple agents collaborate:

```json
"project_topics": {
  "42": {
    "label": "🏗 Dev",
    "agents": ["victor", "archie"],
    "default_agent": "victor"
  }
}
```

Use `@agentname` mentions to address a specific agent in a shared topic.

## Scripts

| Script | Purpose | Trigger |
|--------|---------|---------|
| `telegram_send.sh` | Send messages to topics | Manual / cross-agent |
| `heartbeat.sh` | Run proactive tasks from `heartbeat.md` | Cron |
| `healthcheck.sh` | System health report | Cron (daily) |
| `agent_task.sh` | Delegate tasks between agents | Inter-agent |
| `log_action.sh` | Log external actions to Sheets + file | After side-effects |
| `memory_consolidation.sh` | Merge daily logs → `memory.md` | Cron (weekly) |

### Dedup

`telegram_send.sh` has built-in deduplication: identical messages to the same topic within 60 seconds are silently dropped.

## Memory System

AgentForge provides three layers of memory:

| Layer | Storage | Purpose |
|-------|---------|---------|
| **Conversations** | SQLite + FTS5 | Full message history, searchable |
| **Vault** | SQLite + FTS5 | Structured facts/preferences per agent |
| **Files** | Markdown | `soul.md` (identity), `memory.md` (long-term), `daily/` (learnings) |

The weekly `memory_consolidation.sh` script merges daily learnings into each agent's `memory.md`.

## Todo System

Each agent has a dedicated todo file in the Obsidian vault, automatically injected into the agent's context during every heartbeat invocation.

### File Location

```
vault/Tasks/Agents/<agent>.md
```

Agent-to-file mapping:
- `archie` → `vault/Tasks/Agents/archie.md`
- `catherine` → `vault/Tasks/Agents/catherine.md`
- `christophe` → `vault/Tasks/Agents/christophe.md`
- `victor` → `vault/Tasks/Agents/victor.md`
- `architect` (The Architect) → `vault/Tasks/Agents/the-architect.md`

### File Format

```markdown
# Todos — <Agent>

<!-- Tâches assignées à <Agent> -->

## En cours

## À faire

## Complétés
```

Todos support optional tags: `#projet/name`, `#objectif/name`, or `#autre`.

### Slash Commands

The following slash commands are available for managing todos (defined in `commands/`):

| Command | Description |
|---------|-------------|
| `/todo-add` | Add a todo to an agent |
| `/todo-all` | List all todos for an agent |
| `/todo-next` | Show the next single todo |
| `/todo-nexts` | Show the next few todos |
| `/todo-projet` | Show todos for a specific project tag |
| `/todo-projets` | List all projects that have todos |
| `/todo-goal` | Show todos for a specific goal tag |
| `/todo-goals` | List all goals that have todos |
| `/todo-autres` | Show todos without a project or goal tag |
| `/todo-migrer` | Migrate unchecked todos from a daily note to the Inbox |

### Heartbeat Integration

The `proactive_check` in `heartbeat.sh` automatically reads each agent's todo file and injects its contents into the context before invoking Claude. Agents see their todos on every heartbeat invocation without needing to read the file manually.

## Dependencies

**Core:** Python 3.10+ stdlib only (no pip install required for basic operation)

**Optional extras:**

```bash
pip install agentforge[full]    # requests + faster-whisper
pip install agentforge[dev]     # pytest + pytest-cov
```

| Extra | Package | Purpose |
|-------|---------|---------|
| `full` | `requests>=2.28` | Faster HTTP client (falls back to urllib) |
| `full` | `faster-whisper>=1.0` | Voice note transcription |
| `dev` | `pytest>=7` | Test runner |
| `dev` | `pytest-cov` | Coverage reports |

## External Requirements

- **Claude Code CLI** — must be installed at `$AGENTFORGE_ROOT/.local/bin/claude`
- **Telegram Bot** — create one via [@BotFather](https://t.me/BotFather), enable Forum Topics in your supergroup

---

## Full Installation Guide (Fresh Linux Server)

This is the step-by-step procedure to install AgentForge on a fresh Linux machine (Ubuntu/Debian).

### Prerequisites

```bash
# System packages
sudo apt update && sudo apt install -y python3.12 python3.12-venv git curl

# Node.js (required for Claude Code CLI)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
```

### Step 1 — Create a dedicated user

```bash
sudo adduser --disabled-password --gecos "AgentForge Bot" agentforge
sudo loginctl enable-linger agentforge   # allows systemd user services to run without login
```

### Step 2 — Install Claude Code CLI

```bash
sudo -u agentforge -i   # switch to agentforge user

# Install Claude Code
npm install -g @anthropic-ai/claude-code
# Verify
claude --version
```

> **Note:** Claude Code requires an Anthropic API key or Claude Max subscription. Run `claude` once to authenticate.

### Step 3 — Clone and install AgentForge

```bash
# Still as agentforge user
cd ~
git clone https://github.com/Martin-Rancourt/AgentForge.git
cd AgentForge
./install.sh ~
```

The installer will:
1. Check Python 3.10+ ✓
2. Check Claude CLI ✓
3. Create a virtual environment
4. Install the `agentforge` package
5. Run the interactive `agentforge init` wizard
6. Generate a systemd user service
7. Check for Syncthing

### Step 4 — Set up Telegram

Before running the bot, you need a Telegram Bot + Supergroup:

1. **Create a bot** — Talk to [@BotFather](https://t.me/BotFather) on Telegram:
   - `/newbot` → choose a name and username
   - Copy the **bot token**

2. **Create a Supergroup** with Forum Topics enabled:
   - Telegram → New Group → add your bot → make it a Supergroup
   - Group Settings → Topics → Enable
   - Create one topic per agent (e.g. "Assistant", "Researcher", "Dev")

3. **Get the chat ID and thread IDs**:
   - Send a message in each topic
   - Use `https://api.telegram.org/bot<TOKEN>/getUpdates` to see recent messages
   - Note the `chat.id` (negative number) and each `message_thread_id`

4. **Update config**:
   ```bash
   # Edit .env with your token
   nano ~/.env
   # → AGENTFORGE_TELEGRAM_TOKEN=your_token_here

   # Edit config with your chat ID and thread IDs
   nano ~/bot/config.json
   ```

### Step 5 — Create your agents

```bash
# Create agents matching your Telegram topics
agentforge agent create assistant --model sonnet --thread-id 11
agentforge agent create researcher --model opus --thread-id 12

# Edit each agent's personality
nano ~/agents/assistant/soul.md
nano ~/agents/researcher/soul.md
```

### Step 6 — Start the bot

```bash
# Enable and start the systemd service
systemctl --user daemon-reload
systemctl --user enable --now agentforge

# Verify it's running
systemctl --user status agentforge

# Watch logs
journalctl --user -u agentforge -f
```

### Step 7 — Set up cron jobs (optional but recommended)

```bash
crontab -e
```

Add:

```cron
# Heartbeat — proactive tasks every 30 minutes
*/30 * * * * AGENTFORGE_ROOT=$HOME $HOME/.venv/bin/agentforge heartbeat >> $HOME/logs/heartbeat.log 2>&1

# Daily health check at 08:00
0 8 * * * $HOME/scripts/healthcheck.sh >> $HOME/logs/healthcheck.log 2>&1

# Weekly memory consolidation (Sunday 23:00)
0 23 * * 0 $HOME/scripts/memory_consolidation.sh >> $HOME/logs/consolidation.log 2>&1
```

---

## Syncthing — Cross-Device Knowledge Sync

AgentForge uses [Syncthing](https://syncthing.net/) to sync your knowledge vault (Obsidian vault, agent memory, etc.) across devices. This is optional but recommended if you want to access your bot's brain from your phone or laptop.

### Architecture

```
┌──────────────┐     Syncthing      ┌──────────────┐
│ Linux Server │ ◄──────────────► │    macOS     │
│  (always-on) │                    │  (laptop)    │
└──────┬───────┘                    └──────────────┘
       │
       │  Syncthing
       ▼
┌──────────────┐
│   iPhone     │
│ (Möbius Sync)│
└──────────────┘
```

The Linux server is the **hub** — always on, always syncing. Other devices sync when they're online.

### Linux Server Setup

```bash
# Install Syncthing
sudo apt install -y syncthing

# Enable as a user service (runs without login thanks to lingering)
systemctl --user enable --now syncthing

# Access the web UI
# Syncthing listens on http://localhost:8384
# If remote: ssh -L 8384:localhost:8384 agentforge@your-server
```

**Configure the shared folder:**

1. Open Syncthing web UI (`http://localhost:8384`)
2. **Add Folder** → set the path to your knowledge vault (e.g. `~/obsidian-brain/`)
3. Set a **Folder ID** (e.g. `agentforge-vault`) — you'll need this on other devices
4. Under **Advanced** → set **Folder Type** to "Send & Receive"

### macOS Setup

```bash
# Install via Homebrew
brew install syncthing

# Start as a background service
brew services start syncthing
```

1. Open `http://localhost:8384` in your browser
2. **Add Remote Device** → paste the Linux server's **Device ID** (found in the server's Syncthing UI under Actions → Show ID)
3. On the **Linux server**, accept the incoming device request
4. The shared folder should auto-appear for approval on macOS — accept it
5. Choose a local path (e.g. `~/Documents/agentforge-vault/`)

**For Obsidian:** Point Obsidian's vault to the synced folder. Your bot's knowledge base stays in sync with your laptop.

### iOS Setup (Möbius Sync)

[Möbius Sync](https://apps.apple.com/app/m%C3%B6bius-sync/id1539203216) is the only Syncthing-compatible app for iOS. It costs ~$5 USD (one-time purchase).

1. **Install** [Möbius Sync](https://apps.apple.com/app/m%C3%B6bius-sync/id1539203216) from the App Store
2. Open the app → go to **Settings** → note your **Device ID**
3. On your **Linux server** Syncthing UI:
   - **Add Remote Device** → paste the iOS Device ID
   - Share the `agentforge-vault` folder with this device
4. Back in Möbius Sync:
   - Accept the incoming device connection
   - Accept the shared folder
   - Choose a local location (e.g. under "On My iPhone" or iCloud)
5. **For Obsidian Mobile:** Point Obsidian to the Möbius Sync folder to browse your vault on the go

> **Tip:** Möbius Sync works best with "Background Sync" enabled (Settings → Background Sync → On). iOS may still throttle it, so open the app occasionally to force a full sync.

### Syncthing Tips

- **Device IDs** are the only thing you exchange — no accounts, no cloud, fully P2P encrypted
- **Ignore patterns:** Add a `.stignore` file in your vault root to exclude files:
  ```
  .obsidian/workspace.json
  .DS_Store
  *.tmp
  ```
- **Conflict resolution:** Syncthing creates `.sync-conflict-*` files if two devices edit the same file simultaneously. Resolve manually.
- **Bandwidth:** Initial sync can be slow for large vaults. Subsequent syncs are incremental and near-instant.

---

## Testing

```bash
pip install -e ".[dev]"
pytest                      # Run all 49 tests
pytest --cov=agentforge     # With coverage
```

Tests cover: config validation, message routing, memory manager, vault operations.

## Releases

This project uses [release-please](https://github.com/googleapis/release-please) for automated releases:

1. Use **conventional commits** (`feat:`, `fix:`, `docs:`, `chore:`, etc.)
2. Release-please accumulates changes and opens a **Release PR** with version bump + changelog
3. Merge the Release PR → GitHub Release + git tag created automatically

## License

MIT
