An agentic framework for building purpose-built AI bots in Slack. Powered by Claude Code with installable skills, persistent memory, and per-channel isolation.
Same framework, different soul + skills = different agent. A LinkedIn content bot, a paid search optimizer, a growth marketing assistant — each is an Engram instance with its own personality and capabilities.
git clone <your-repo-url> ~/engram
cd ~/engram
./install.shThe installer handles dependencies (Homebrew, tmux, Bun, Node, jq, Hindsight memory plugin), launchd services, and cron jobs. It then launches the setup wizard which walks you through:
- Claude Code authentication (OAuth or API key)
- Slack app creation (opens the page, tells you exactly what to click)
- Token collection and validation
- Personalizing your agent (name, timezone, background)
- Test message to verify everything works
When the wizard finishes:
./micro-harness/start-engram.shDM your bot in Slack — it should respond! 🎉
launchctl load ~/Library/LaunchAgents/com.engram.plistSlack (DMs + channels)
│
slack-bridge.ts ← Socket Mode
│
┌─────┼──────────┐
▼ ▼ ▼
Your #growth #marketing ... (auto-provisioned)
DM
│
All instances inherit from git root:
├── SOUL.md (personality)
├── CLAUDE.md (orchestration)
├── .claude/rules/ (guardrails)
└── .claude/skills/ (capabilities)
- Your DM → Full personal context, memory, self-improvement
- Team channels → Auto-provisioned on first @mention. No config needed.
- Skills → On-demand Claude Code skills that define what your agent can do
- Memory → Hindsight provides per-channel isolated long-term memory
- Crash recovery → Messages queued locally. Nothing lost on restart.
Engram leverages Claude Code's native directory resolution. The .claude/ directory at the git root provides rules, skills, and settings to every context automatically — no symlinks, no copying, no template generation.
Claude Code also walks up parent directories for CLAUDE.md files. When it starts in contexts/owner-dm/, it loads both the root CLAUDE.md (shared orchestration) and the context's own CLAUDE.md (optional overrides).
Your agent's identity lives in SOUL.md at the repo root. Edit this to change who your agent is — personality, voice, mission. This is read at the start of every session.
CLAUDE.md at the repo root defines how your agent works — session startup protocol, special triggers (heartbeats, self-improvement), user info, safety rules. This is auto-loaded by Claude Code for every context.
Skills give your agent capabilities. Each skill is a folder with a SKILL.md:
.claude/skills/
├── linkedin-posting/
│ ├── SKILL.md # Instructions + frontmatter
│ └── references/
│ ├── post-templates.md
│ └── hashtag-guide.md
├── content-research/
│ └── SKILL.md
└── brand-voice/
├── SKILL.md
└── references/
└── tone-examples.md
Skills load on-demand — only names and descriptions are scanned at startup (~100 tokens each). Full content loads when Claude auto-invokes based on context or when the user types /skill-name. This means 5-15 skills add negligible overhead.
Adding a skill: Copy .claude/skills/_template/SKILL.md into a new directory under .claude/skills/ and fill it in. The template at .claude/skills/_template/ is the single source of truth for SKILL.md shape — frontmatter fields (name, description, when_to_use, last_reviewed) and required body sections (Overview, Triggers, Instructions, Examples).
Always-on behavioral guardrails. Every file in .claude/rules/ is loaded at startup for every message. Use for safety rules, formatting preferences, decision-making patterns.
A shared knowledge base at the repo root. Add domain-specific knowledge (like an Obsidian vault) that all contexts can reference.
Most channels don't need their own CLAUDE.md — the root files handle everything. But if a channel needs specific behavior (e.g., "never discuss competitors in this channel"), add a CLAUDE.md in that context's directory. Claude loads both root and local CLAUDE.md files, with local taking precedence on conflicts.
To create a specialized agent (e.g., a LinkedIn content bot):
- Edit
SOUL.md— Define personality and mission for content creation - Edit
CLAUDE.md— Set up user info, relevant triggers, workflow - Add skills — Drop
linkedin-posting/,content-research/,brand-voice/into.claude/skills/ - Add rules — Any always-on guardrails in
.claude/rules/ - Add knowledge — Domain docs in
vault/
The micro-harness (Slack bridge, heartbeat, watchdog) stays the same. Your agent's behavior is entirely defined by its soul, skills, and rules.
# See all running instances
tmux attach -t engram
# Watch bridge logs
tail -f /tmp/engram.log
# Check system health
~/engram/micro-harness/watchdog.shengram/
├── SOUL.md ← Agent personality & identity
├── CLAUDE.md ← Orchestration & session protocol
├── .claude/
│ ├── rules/ # Always-on guardrails (loaded every message)
│ │ ├── safety.md
│ │ ├── slack-formatting.md
│ │ ├── decision-preferences.md
│ │ └── ...
│ ├── skills/ # On-demand capabilities
│ │ └── (your skills here)
│ └── settings.json # Model, compaction, permissions
├── vault/ # Shared knowledge base
├── contexts/
│ └── owner-dm/ # Your DM (created by setup.sh)
│ ├── CLAUDE.md # Minimal: "full access DM context"
│ ├── .hindsight/ # Per-channel memory config
│ └── memory/ # Working memory
│ └── (auto-provisioned channels get created here)
├── micro-harness/
│ ├── slack-bridge.ts # Session router
│ ├── start-engram.sh # System startup
│ ├── heartbeat.sh # Periodic check-in (cron)
│ ├── watchdog.sh # Health monitor (cron)
│ ├── trigger.sh # Generic triggers (cron)
│ ├── templates/ # Templates for new channels
│ └── queue/ # Message queue (crash recovery)
├── scripts/
│ └── context-usage.sh # Context window usage estimator
├── install.sh # One-command setup
├── setup.sh # Interactive setup wizard
└── .env # Your secrets (not committed)
At 2 AM daily, a cron job triggers a self-improvement cycle. It reviews conversations across all channels, extracts insights, and updates behavioral rules. This is how Engram gets better over time.
Every 30 minutes (8 AM – 11 PM), a heartbeat checks in with the DM instance for proactive tasks — calendar, emails, or anything you've configured.
Bot doesn't respond to DMs:
- Check
.env— isENGRAM_OWNER_USER_IDset to YOUR Slack user ID? - Check logs:
tail -f /tmp/engram.log
Bot doesn't respond to @mentions:
- Invite the bot to the channel first (
/invite @your-bot-name) - Check
app_mentionevent subscription is enabled
"tmux session 'engram' not found":
- Start it:
./micro-harness/start-engram.sh
Bridge crashes on startup:
- Check
CLAUDE.mdandSOUL.mdexist at repo root - Check
.envhas all required values - Run
cd micro-harness && bun run slack-bridge.tsto see errors
Slack App Setup (manual reference)
-
Go to api.slack.com/apps → Create New App → From scratch
-
Enable Socket Mode:
- Left sidebar → Socket Mode → Toggle on
- Give the token a name (e.g. "engram") → Generate
- Copy the
xapp-...token →SLACK_APP_TOKEN
-
Add bot permissions:
- Left sidebar → OAuth & Permissions → Bot Token Scopes
- Add:
chat:write,files:read,files:write,channels:read,channels:history,groups:read,groups:history,im:read,im:history,app_mentions:read
-
Enable DMs with the bot:
- Left sidebar → App Home → scroll to Show Tabs
- Check Messages Tab → enable "Allow users to send Slash commands and messages from the messages tab"
-
Subscribe to events:
- Left sidebar → Event Subscriptions → Toggle on
- Subscribe to bot events → Add:
message.channels,message.groups,message.im,app_mention
-
Install the app:
- Left sidebar → Install App → Install to Workspace → Approve
- Copy the
xoxb-...token →SLACK_BOT_TOKEN
-
Get IDs:
- Bot's User ID: click bot profile → Copy member ID →
SLACK_BOT_USER_ID - Your User ID: click your profile → Copy member ID →
ENGRAM_OWNER_USER_ID - DM Channel: open DM with bot → right-click → Copy link → ID at end →
ENGRAM_DM_CHANNEL
- Bot's User ID: click bot profile → Copy member ID →
| Variable | What it is | Looks like |
|---|---|---|
ANTHROPIC_API_KEY |
Anthropic API key | sk-ant-... |
SLACK_APP_TOKEN |
Socket Mode app-level token | xapp-... |
SLACK_BOT_TOKEN |
Bot User OAuth Token | xoxb-... |
SLACK_BOT_USER_ID |
Bot's Slack member ID | U07... |
ENGRAM_OWNER_USER_ID |
Your Slack member ID | U07... |
ENGRAM_DM_CHANNEL |
DM channel with bot | D07... |
See CLAUDE.md and the micro-harness/ source for the current architecture. The bridge (micro-harness/slack-bridge.ts) is the single source of truth for runtime behavior.