Skip to content

Dembrane/sam

Repository files navigation

Sam

An engineering coworker. Lives in Slack, picks up Linear tickets, opens PRs, does what you teach it.

Sam's behavior is defined by this repo. Sam can improve by proposing changes via PR.

Sam

What Sam needs to work

Sam

  • To use Sam. It must be connected to a communication channel. Slack is the first choice.
  • To pick up work, Sam must have the relevant tokens, rights, permissions, access to "do stuff". This is important to be secure as you would with any other coworker. Examples: Create a GitHub PAT and configure it as a secret. Give it API keys for Tally Forms, or Framer wherever you need Sam to perform work.
  • For project management and visibility, I chose Linear. Any other todo, kanban, GitHub issues/projects also work. Helpful to see blockers and big arcs of work at a glance.

General principles

  • Self-maintaining: Since Sam is a codebase, Sam can reflect and attempt improvements to itself. You being the mentor are responsible for reviewing these as well has being motivated to improve Sam yourself.
  • Multiplayer: Sam lives in Slack, where the team already talks, uses Slack's mature features like notifications, threads, reactions.
  • Event-driven: Linear and GitHub events (Not Built in yet), Slack mentions wake Sam up.
  • Duplicatability: Sam works in a container with its own state.

My motivations - Why Sam was made?

  • Building a product today - writing requirements is at the (almost) same abstraction level as writing code. So if someone knows what they want to build, they should be enabled to do it. Sam is the communication, execution, maintenance layer for any codebase(s). I can imagine where we can easily ship docs, fix bugs, etc. A system like Sam also incentivizes good CI/CD practices. This repo itself almost demanded them. For a small team, this can be a real boost in productivity.

  • Linear's slack agent is really helpful. Sam is heavily inspired by it. I once asked it to write a skill and surprisingly it did, but was limited. I thought why not make the agent more powerful and give it more access and also it's own codebase.

  • How I tried to use Linear's slack agent and failed

Linear Slack Agent

  • General trend of making Claude Code harnesses for themselves with hooks, Obsidian as memory. Self healing through hooks. Single-player power-ups for individual work. Had a similar instinct to create a system that works in a team context.

Decisions?

  • 🟢 Respond to only one message at a time. Sam is free to spin up subagents for complex tasks, but never do two tasks at once. Human focus is like a rate limiter not a bottleneck. If parallelization is needed, spin up another Sam.

  • 🟡 Split capabilities and skills. Capabilities are what Sam always knows. Skills are patterns Sam reaches for. But both of them are very similar in nature. Reason this was done because Sam wasn't reading some skills in detail and not triggering them when they were relevant as a result. (Better skill descriptions is a potential direction)

  • 🟡 Using 3.5 Flash for the main agent. It is fast, cheap. Ideally all requests go through Opus 4.7. Opus is used as a mentor agent to review Flash's work and suggest improvements to the source. Still on the fence about 3.1 Pro for heavy execution work. Exploration to find the best model fit is ongoing.

Layout

src/
  identity.md         who Sam is
  scope.md            what Sam refuses to do
  capabilities/       what Sam always knows
  skills/             patterns Sam reaches for
  runtime/            daemon and supporting code

Capabilities, skills, and scope

All markdown under src/, loaded differently:

  • Capability: identity-shaped, always relevant. Hot-loaded in full into every session.
  • Skill: a specific pattern triggered when conditions match. Frontmatter (name, description, when_to_use, path) emitted as a catalog; Sam reads the body when triggered.
  • Scope (src/scope.md): the boundary file — what Sam refuses to do, who Sam treats as principal, which channels are in-bounds. Capabilities + skills define what Sam does; scope defines what Sam doesn't.

Rule of thumb: known on every message → capability. Known sometimes → skill. A "no" or a boundary → scope.

See src/capabilities/self-maintenance.md for the frontmatter convention and the flow for proposing changes.

Setup

Local (Docker)

cp .env.example .env
# fill in .env with your own values
docker compose up -d --build
docker compose logs -f sam

State persists to ./data/ (mounted at /data in the container, gitignored).

Note There was once a local setup available which plugged into Claude Code. It is no longer supported but feel free to hack it in again. Moved away because it was not ergonomic to login to CC on the GCP container and I didn't want to pay again for another API key.

For a long-running deploy, follow infra/ (Terraform). Single-instance Cloud Run, GCS-backed state, Workload Identity Federation for CI deploys from GitHub Actions.

See infra/README.md.


open items

  • use calendar over cron? set reminders, listen to webhooks on cal events? more visibility and also we can log times in the cal when sam works and on what. important events are tracked, sam can kick off a smoke test 1d before, see if all reqs are met.

  • how to bring changes upstream to dembrane/sam? maybe add to daily maintenence? pull from dembrane/sam the latest changes to the substrate and intentionally have divergent changes of multiple "instances of sam"? and then also as a measure have the changes that any instance makes back into sam? of course users should be able to disable this.

About

engineering coworker

Resources

License

Stars

Watchers

Forks

Contributors