lituanic
v0.1.8
Published
AI coworker for solo founders. Picks up Linear issues, writes code, sends email, and reports back to Slack.
Maintainers
Readme
Lituanic
AI coworker for solo founders. Picks up Linear issues, writes code, sends email, and reports back to Slack — autonomously.
Named after the 1933 transatlantic flight by Steponas Darius and Stasys Girenas — two people, one plane, crossing the Atlantic with what they had.
Thesis
Most agent frameworks build orchestration for teams of humans managing fleets of agents. Lituanic solves the opposite: one person running an entire company through one agent.
This is what smart contracts promised — code-first, zero-human operations. Lituanic delivers it with LLMs: an AI coworker that manages projects, writes code, ships products, handles email, and reports back to Slack.
Lituanic is a thin wiring layer on the Claude Agent SDK. The SDK does all the hard work — agent loop, tool calling, sessions, compaction, subagents, sandboxing. Lituanic wires it to Slack and adds opinionated defaults. When Anthropic ships an SDK update, Lituanic gets better for free.
~1,600 lines of TypeScript. 6 built-in integrations. 3 dependencies.
Built-in integrations
| Integration | How | Env vars |
|---|---|---|
| Slack | Typed MCP tools (reply, react, upload) + Bolt gateway | SLACK_BOT_TOKEN, SLACK_APP_TOKEN |
| Linear | SKILL.md + GraphQL API via curl | LINEAR_API_KEY |
| 1Password | SKILL.md + op CLI via Bash | OP_SERVICE_ACCOUNT_TOKEN |
| Google Workspace | SKILL.md + gws CLI via Bash | GWS_CLIENT_ID + credentials |
| Browser | SKILL.md + agent-browser CLI via Bash | None (optional: KERNEL_API_KEY) |
| GitHub | SKILL.md + gh CLI via Bash | GH_TOKEN |
Slack is the only typed MCP tool because mistakes are visible to humans. The other 5 use CLI tools or APIs via Bash, which the SDK provides for free.
Adding an integration = writing one SKILL.md file + adding env checks to doctor.ts.
Slack app setup
Create a Slack app at api.slack.com/apps:
- Create New App → From scratch → pick your workspace
- Socket Mode → Enable Socket Mode → generate an app-level token with
connections:writescope → save asSLACK_APP_TOKEN(starts withxapp-) - OAuth & Permissions → add Bot Token Scopes:
app_mentions:read— receive @mentionschat:write— send messagesim:history— read DM historyim:read— open DMsreactions:write— add emoji reactionsfiles:write— upload files (screenshots, PDFs)
- Event Subscriptions → Enable Events → Subscribe to bot events:
app_mention— triggers on @mentions in channelsmessage.im— triggers on direct messages
- Install to Workspace → copy Bot User OAuth Token → save as
SLACK_BOT_TOKEN(starts withxoxb-) - App Home → enable "Messages Tab" so users can DM the bot
Quick start
bunx lituanic init my-agent
cd my-agent// lituanic.config.ts
import { defineConfig } from "lituanic";
export default defineConfig({
name: "my-agent",
model: "claude-sonnet-4-6",
slack: {
botToken: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
},
});bun startYour agent is live in Slack with access to: file system, shell, web search, subagents, and any CLI tool installed on the host.
Check your setup
$ lituanic doctor
✓ Claude auth: OAuth token set (Claude Pro/Max subscription)
✓ op CLI: Installed
✓ OP_SERVICE_ACCOUNT_TOKEN: Set — 1Password secrets available
✓ Slack bot token: Set
✓ Slack app token: Set
✓ Linear API key: Set
✓ gh CLI: Installed
✓ GH_TOKEN: Set
! agent-browser CLI: Not found — install: npm i -g agent-browser && agent-browser install
! gws CLI: Not found — install: npm i -g @googleworkspace/cli
! GWS credentials: Missing — Google Workspace disabled
✓ Backup: Last backup 6h ago
9 ok, 3 warnings, 0 failuresAdd a skill
mkdir -p .claude/skills/deploy
cat > .claude/skills/deploy/SKILL.md << 'EOF'
---
name: deploy
description: Deploy to production. Use when asked to "deploy", "ship it", or "push to prod".
---
1. Run tests: `bun test`
2. Push: `git push origin main`
3. Wait for CI, then check health
4. Report status in Slack
EOFNo code change. No restart. The agent immediately knows how to deploy.
Add an MCP server
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
}
}Architecture
┌──────────────────────────────────────────────────────────────┐
│ lituanic (~1,600 LOC) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────────────┐ │
│ │ gateway.ts │ │ sessions.ts │ │ Claude Agent SDK │ │
│ │ │ │ │ │ query() │ │
│ │ Slack Bolt │ │ thread → │ │ │ │
│ │ Webhooks │──│ session_id │─▶│ Built-in tools: │ │
│ │ Cron │ │ resume │ │ Bash Read Write Edit │ │
│ │ Chan queue │ │ │ │ Glob Grep WebFetch │ │
│ └─────────────┘ └─────────────┘ │ WebSearch Agent Skill│ │
│ │ │ │
│ ┌─────────────┐ ┌─────────────┐ │ SDK handles: │ │
│ │ tools.ts │ │ doctor.ts │ │ • Agent loop │ │
│ │ │ │ │ │ • Session persist │ │
│ │ slack_reply │ │ env checks │ │ • Compaction │ │
│ │ slack_react │ │ CLI checks │ │ • Subagents │ │
│ │ slack_up.. │ │ 1P + backup │ │ • Sandbox │ │
│ └──────┬──────┘ └─────────────┘ │ • File checkpointing │ │
│ │ │ • Thinking │ │
│ ┌──────┴──────┐ │ • Permissions │ │
│ │ format.ts │ │ • Notifications │ │
│ │ md → mrkdwn │ │ • Cost tracking │ │
│ └─────────────┘ └──────────────────────┘ │
│ │
│ .claude/skills/ (loaded by SDK) │
│ ├── slack/SKILL.md │
│ ├── linear/SKILL.md │
│ ├── op/SKILL.md │
│ ├── gws/SKILL.md │
│ ├── browser/SKILL.md │
│ └── github/SKILL.md │
└──────────────────────────────────────────────────────────────┘What Lituanic owns (the wiring)
| File | LOC | Purpose |
|---|---|---|
| gateway.ts | 300 | Slack Bolt + webhooks (Linear state machine) + cron + per-channel queue |
| think.ts | 262 | query() wrapper: session resume, effort routing, cost optimization, canUseTool, progress, debug logging |
| index.ts | 210 | Daemon boot, typing indicator, notification forwarding |
| init.ts | 184 | lituanic init scaffolding (config, .env, .env.op, .gitignore) |
| doctor.ts | 175 | Integration health checks (env vars, CLIs, 1Password, backup status) |
| config.ts | 137 | Zod config with opinionated defaults |
| cli.ts | 87 | CLI: start, init, doctor, health, version |
| sessions.ts | 75 | Slack thread to SDK session_id mapping |
| memory.ts | 65 | Daily logs + per-channel state |
| tools.ts | 63 | Slack MCP tools: reply, react, upload (only typed integration) |
| format.ts | 23 | Markdown → Slack mrkdwn converter (shared by index + tools) |
| Total | ~1,581 | |
What the Agent SDK owns (delegated)
Every time Anthropic ships an SDK update, Lituanic gets better for free.
| SDK capability | What we skip building |
|---|---|
| Agent loop + tool calling | No custom loop code |
| Built-in Bash, Read, Write, Edit, Glob, Grep | No tool reimplementation |
| Built-in WebSearch, WebFetch | No HTTP wrappers |
| Skill tool + .claude/skills/ loading | No skill discovery code |
| CLAUDE.md loading via settingSources | No system prompt assembly |
| System prompt (claude_code preset) | No prompt engineering |
| Session persistence + resume + fork | Just store the session_id |
| Context compaction | No manual context management |
| Subagent orchestration (Agent tool) | No multi-agent plumbing |
| Sandbox (filesystem + network isolation) | No Docker code |
| canUseTool callback | Inline security, no separate module |
| File checkpointing + rewind | Free rollback on error |
| Adaptive thinking | Automatic on Opus/Sonnet 4.6 |
| Effort control (low/medium/high/max) | One line: effort: "medium" |
| Environment passthrough | env: process.env |
| Model fallback | fallbackModel: "claude-haiku-4-5" |
| Notification hooks | Forward to Slack |
| Cost tracking + budget limits | maxBudgetUsd: 5.0 |
| MCP server management | Connect any MCP server |
Integration philosophy
Typed MCP tools SKILL.md + CLI via Bash
(mistakes are costly) (CLI teams maintain their tools)
──────────────────── ──────────────────────────────
Slack ✓ slack_reply
✓ slack_react
✓ slack_upload_file
Linear ✓ GraphQL API via curl
1Password ✓ op CLI
Google Workspace ✓ gws CLI
Browser ✓ agent-browser CLI
GitHub ✓ gh CLIWhy Slack gets typed tools: wrong-channel prevention, thread enforcement, mrkdwn formatting, file uploads. Mistakes are immediately visible to humans.
Why everything else is SKILL.md + CLI: the linear CLI, op CLI, and googleworkspace CLI are well-designed, typed, maintained by their respective companies. When they ship updates, our agent uses new features immediately with zero code changes. We maintain knowledge (SKILL.md), not integration code.
Session continuity
Slack thread = Agent SDK session. Follow-ups resume with full context.
User: @agent set up the new API endpoint
Agent: [reads code, creates files, runs tests, reports back]
└── session stored: channel:thread → sess_abc123
User: (same thread) now add rate limiting
Agent: [resumes sess_abc123 — knows what was built, adds rate limiting]The SDK handles context window management, compaction, and session persistence to disk. Lituanic just maps Slack threads to session IDs.
Subagents
Claude spawns parallel workers via the built-in Agent tool:
User: @agent research competitors, build the landing page, and set up CI
Agent: Working on these in parallel.
├── [Subagent] Researching competitors via WebSearch...
├── [Subagent] Building landing page with Read/Write/Edit...
└── [Subagent] Setting up CI with Bash...
Agent: All three done. Here's the summary.Claude decides when to parallelize. No orchestration code needed.
Skills
Skills are SKILL.md files in .claude/skills/. The SDK loads them via settingSources: ["project"] and invokes them via the Skill tool when the task matches the description.
.claude/skills/
├── slack/SKILL.md # When to use Slack tools, formatting rules
├── linear/SKILL.md # CLI commands, workpad pattern, autonomous work
├── op/SKILL.md # Secret reading, security rules, patterns
├── gws/SKILL.md # Email, calendar, drive commands
├── browser/SKILL.md # Web browsing, screenshots, form filling
└── github/SKILL.md # PRs, issues, CI, releasesAdd your own:
.claude/skills/
└── deploy/SKILL.md # Your deployment procedureThe description in frontmatter is how Claude decides whether to load the skill. Write it like a search result — specific, with trigger phrases.
Configuration
// lituanic.config.ts
import { defineConfig } from "lituanic";
export default defineConfig({
name: "my-agent",
model: "claude-sonnet-4-6",
fallbackModel: "claude-haiku-4-5",
cwd: "/home/agent/workspace",
slack: {
botToken: process.env.SLACK_BOT_TOKEN!,
appToken: process.env.SLACK_APP_TOKEN!,
channel: "C0AKA6Y53D2", // ops channel for errors + notifications
},
webhook: {
port: 9100,
routes: {
"/webhook/linear": {
secret: process.env.LINEAR_WEBHOOK_SECRET,
verify: "hmac-sha256",
},
},
},
schedule: [
{ cron: "0 9,15 * * *", prompt: "Run the x-post skill.", timezone: "Europe/Madrid" },
{ cron: "*/15 * * * *", prompt: "Check Linear for assigned issues and work on them." },
],
maxBudgetUsd: 5.0,
maxTurns: 50,
sandbox: false,
});Authentication
Two options — use either one:
Option A: Claude Pro/Max subscription (recommended)
Uses your existing subscription. No per-token API costs.
# On a machine with a browser (laptop), generate a 1-year token:
claude setup-token
# → Your OAuth token (valid for 1 year): sk-ant-oat01-...
# Store in 1Password, then reference in .env.op:
# CLAUDE_CODE_OAUTH_TOKEN=op://Lituanic/Claude/oauth-token
# Or set directly:
export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...
bun startOption B: API key (pay-per-use)
export ANTHROPIC_API_KEY=sk-ant-...
bun startBoth options work with 1Password on VPS: op run --env-file=.env.op -- bun start
Other secrets
export SLACK_BOT_TOKEN=xoxb-...
export SLACK_APP_TOKEN=xapp-...Deploy
Everything lives in deploy/ — systemd unit, backup cron, bootstrap script, and 1Password templates.
# On a fresh Ubuntu/Debian VPS
bash deploy/setup.sh
# Set the 1Password bootstrap token (root-only)
sudo mkdir -p /etc/systemd/system/lituanic.service.d
sudo tee /etc/systemd/system/lituanic.service.d/override.conf <<EOF
[Service]
Environment=OP_SERVICE_ACCOUNT_TOKEN=ops_YOUR_TOKEN
EOF
sudo chmod 600 /etc/systemd/system/lituanic.service.d/override.conf
sudo systemctl daemon-reload && sudo systemctl start lituanicThe systemd unit (deploy/lituanic.service) runs op run --env-file=.env.op -- bun start with hardened security: NoNewPrivileges, ProtectSystem=strict, ProtectHome=read-only, PrivateTmp.
Daily backups via deploy/backup.sh sync data/ to Google Drive with rclone. lituanic doctor warns if the last backup is older than 48 hours.
Health check built in: GET :9200/health returns JSON.
Comparisons
vs. Pi-mom
| | Pi-mom | Lituanic | |---|---|---| | Codebase | Closed-source npm + 8 monkey patches | ~1,600 LOC, open source | | Concurrency | Serial per channel, no subagents | SDK subagents, parallel work | | Sessions | context.jsonl (custom, fragile) | SDK session persist + resume | | Integrations | Custom extensions in host process | Skills + CLI via Bash | | Config | Undocumented settings.json | Zod-validated TypeScript |
vs. NanoClaw
| | NanoClaw | Lituanic | |---|---|---| | Runtime | Node.js + Docker per group | Bun, single process | | Parallelism | 5 containers, per-group serial | SDK subagents, Claude decides | | Storage | SQLite | Filesystem | | Channels | WhatsApp, Telegram, Discord, Slack, Gmail | Slack + webhooks | | Design | Multi-group multi-container | Single operator |
vs. OpenClaw
| | OpenClaw | Lituanic | |---|---|---| | Scope | 20+ channels, 5400+ skills, voice, canvas | Slack + 6 built-in skills | | Codebase | 19,800+ commits | ~1,600 LOC | | Security | 500+ open issues | Minimal surface, single tenant | | Design | Everything for everyone | One founder, one company |
Design decisions
Why Claude only. When you bet on one model, you use every feature: adaptive thinking, Agent SDK, skills, sessions, subagents, compaction. Multi-provider abstraction means lowest-common-denominator.
Why Slack only. Slack IS the control plane. Every founder already has it open. Adding 20 messaging platforms is OpenClaw's problem, not ours.
Why no database. Files are inspectable, portable, diffable, git-native. Directory structure = schema. The SDK persists sessions to ~/.claude/projects/. We persist daily logs and thread mappings to data/.
Why skills over typed tools. CLI tools (op, gws) and APIs (Linear GraphQL) are maintained by their respective companies. When they ship updates, our agent benefits immediately. We maintain knowledge (SKILL.md), not integration code. Zero maintenance surface for 3 of 4 integrations.
Why parasite architecture. The Claude Agent SDK is backed by a $10B+ company investing heavily in making agents work. Every improvement to the SDK — better compaction, faster loop, new tools, improved sandbox — flows directly to Lituanic with a version bump. We write the thinnest possible wiring layer and get out of the way.
Principles
- Parity. Whatever a human can do through a UI, the agent achieves through tools.
- Atomic primitives. Bash, Read, Write, Edit — not
analyze_and_publish. - Knowledge over code. New capabilities = new SKILL.md files, not new TypeScript.
- Maximum parasitism. Delegate everything possible to the Agent SDK. Own only the wiring.
- Files as interface. Inspectable, portable, diffable, versioned.
- Single operator. One agent, one owner, one Slack. Won't scale to 100 users. Doesn't need to.
- Timeless. Small surface area. Version 1.0 should last years.
License
MIT
