Authoring Your Company with an AI Assistant
A Crewlet company is described in YAML: a mission, an org chart, seats with backstories, policies, integrations. That is a lot of surface to write from a blank file — so Crewlet ships the pieces an AI assistant needs to write it with you and check its own work.
Three things make this work, and you can use any of them on their own:
| Piece | What it gives you |
|---|---|
crewlet schema | JSON Schema generated from the models — the authoritative field list, for your editor, your CI, or an agent |
crewlet validate --json | Machine-readable errors with exact field paths, so a fix loop converges |
The company-architect skill | An interview script, the invariants, and the write → validate → fix loop |
Walkthrough
Section titled “Walkthrough”End to end, from nothing to a running company. The quickstart builds the same shape by hand if you’d rather see every field explained first.
1. Give your assistant the skill
Section titled “1. Give your assistant the skill”Claude Code discovers skills on disk. From a checkout:
mkdir -p ~/.claude/skills && cp -r skills/company-architect ~/.claude/skills/No checkout, or a different assistant? The skill is one self-contained markdown file with absolute links — fetch it and paste or attach it. See Installing the skill for per-tool detail.
2. Say what you want
Section titled “2. Say what you want”Set up a Crewlet company for a small dev-tools startup — a CEO, a CTO with two engineers, and a PM.
3. Answer the interview
Section titled “3. Answer the interview”It won’t dump YAML at you first. It asks what the company does, who’s on it, where you sit in the chart, which surfaces the work lives on, and what model and budget to use. Give rough answers — it proposes a concrete org chart and you correct it. It should also, without being asked:
- put you in the chart as a human seat managing the top agent
- keep every secret as a
${VAR}, never a literal - skip integrations on the first pass (step 8 adds them)
- warn you that handles are effectively permanent
4. It writes and checks its own work
Section titled “4. It writes and checks its own work”You get company.yaml (Tier B — the company) and config.yaml
(Tier A — the infrastructure). After every edit it runs:
crewlet validate company.yaml --jsonand fixes each reported path until valid is true. It should tell you
which rung of the validation ladder it
used — full crewlet fidelity, a plain JSON Schema validator, or
reading the schema. None of this needs your API keys, so the whole
design pass happens before you set up a single account.
5. Fill in the environment
Section titled “5. Fill in the environment”The config references variables; you supply the values. Ask the
assistant to list every ${VAR} it used — a missing one resolves to an
empty string and fails later, deep in a turn.
cp .env.example .env && docker compose up -d # Pulsar + PostgreSQL
export CREWLET_API_TOKEN_FOUNDER="$(openssl rand -hex 32)"export ANTHROPIC_API_KEY="sk-ant-..."export OPENAI_API_KEY="sk-..." # embeddingsexport SLACK_FOUNDER_USER_ID="U0FOUNDER" # your Slack member ID6. Run it
Section titled “6. Run it”crewlet run config.yaml --import-company company.yaml7. Watch the first turn
Section titled “7. Watch the first turn”Open http://localhost:8000/. A company with no integrations has no inbound work, which is why the first pass puts a five-minute schedule on the top seat purely to prove the loop:
schedules: - name: hello-crewlet cron: "*/5 * * * *" task: "Write a short note on what the company should focus on this week."Within five minutes the CEO goes Working, steps through Plan →
Execute → Review, and returns to Idle — every prompt and tool call
inspectable. That’s the engine, your model, and your config all
confirmed working, with no external account involved. Delete the
schedule once real work arrives.
8. Add one integration at a time
Section titled “8. Add one integration at a time”Now go back to the assistant:
Add Slack so the team can talk in channels and DM me.
Pick your stack in Choosing your stack, create the accounts it names (the assistant writes config, it can’t create a Slack app for you), then let it wire the config and re-validate. One integration per pass — a failure is then unambiguous.
Tier B is live-editable, so applying a change is
crewlet config import company.yaml --force, no restart. Full worked
reference with everything connected:
examples/nimbus.company.yaml.
Why not just point an assistant at the docs
Section titled “Why not just point an assistant at the docs”Two reasons the raw docs aren’t enough on their own.
The surface is large and strict. Tier B validates through Pydantic
models that forbid unknown keys, so a plausible-but-invented field name
(responsibilites, leed, commnad) is a hard error, not a silent
no-op. An assistant working from prose will occasionally invent one.
The expensive mistakes aren’t type errors. Choosing a handle you
later rename, putting a secret in the config file, or confusing
integrations.plane.project (routing identity) with
knowledge.plane_projects (read scope) all produce a valid config
that behaves wrong. Those are judgement calls, and they’re what the
skill front-loads.
The schema fixes the first problem. The skill fixes the second.
Without Crewlet installed
Section titled “Without Crewlet installed”Config authoring naturally happens before installation — you design
the company, then set up the infrastructure to run it. So the schema is
deliberately a static file with no dependency on the crewlet
binary: an assistant fetches it from a URL and validates against it
with any standards-compliant JSON Schema validator (jsonschema,
ajv), or by reading it.
It carries more than field names. Because the config models forbid unknown keys and the cross-field rules are encoded alongside their Python validators, a schema-only check catches:
- unknown keys, at every level including roles, units, and MCP servers
- wrong types, and bad enums (
kind: robot,type: openaii) - malformed handles, and cron expressions with the wrong field count
- a human seat with no
contactidentity - Confluence and Plane both enabled, and a
knowledge.*scope list for the backend that isn’t active
Three things still need the binary, and the skill tells the assistant to check them by reading:
| Gap | Why the schema can’t |
|---|---|
lead / manages naming a role or unit that exists | Reference integrity across the document — not expressible in JSON Schema |
| Real IANA timezone | Needs the timezone database |
Cron semantics (99 * * * * has the right shape) | Needs a cron parser |
The two encodings are held in sync by
tests/test_cli/test_schema_rules.py, which runs every rule through
both paths and fails if they disagree — a schema that quietly diverges
from the loader would be worse than no schema, because an assistant
would trust it.
The validation loop
Section titled “The validation loop”The property that makes automated authoring safe:
crewlet validate company.yaml --json{ "valid": false, "tier": "company", "errors": [ { "path": "roles.0.backstroy", "message": "Extra inputs are not permitted", "type": "extra_forbidden" }, { "path": "units.0.leed", "message": "Extra inputs are not permitted", "type": "extra_forbidden" } ]}Every offending field, with its exact path, all at once — so an
assistant fixes them in one pass instead of re-guessing. Exit code is
0 when valid, 1 otherwise.
It needs no credentials, no database, and no network. Tier B stores
${VAR} references verbatim and resolves them at engine start (see
Configuration § Environment variables),
so a complete config validates before any secret exists. You can draft
and check an entire company offline.
Validation is deep: it builds the Organization, so unknown unit leads,
bad cron expressions, invalid timezones, human seats with no contact
identity, and the Confluence-XOR-Plane rule all fail here rather than at
run time.
--tier auto (the default) picks the model from the file: Tier B
requires a top-level name and Tier A forbids it, so the split is exact.
Force it with --tier company / --tier bootstrap.
Editor autocomplete
Section titled “Editor autocomplete”The same schema drives your editor. Add a modeline to the top of the file — with the YAML Language Server (built into VS Code’s YAML extension, and available in Neovim, JetBrains, and Helix) you get completion, inline docs from the field docstrings, and typo squiggles as you type:
# yaml-language-server: $schema=https://docs.crewlet.ai/schema/company.schema.jsonname: "Acme AI"Or generate it locally and point at the file:
crewlet schema company -o schema/company.schema.jsoncrewlet schema bootstrap -o schema/bootstrap.schema.jsonBoth are also checked into schema/ in the repo. They
are generated artifacts — a test regenerates and compares them, so they
cannot drift from what the loader accepts.
Wire it into CI to catch a bad config before it reaches the engine:
crewlet validate company.yaml --json || exit 1The company-architect skill
Section titled “The company-architect skill”skills/company-architect/SKILL.md
is a prompt for an AI assistant. It carries the interview script, the
invariants that the schema can’t express, and the validation loop above.
It is written provider-neutral — it’s a markdown file, not a vendor format — so it works anywhere you can give an assistant instructions.
Claude Code discovers skills automatically. Install it for one project or for every project:
# this project onlymkdir -p .claude/skills && cp -r skills/company-architect .claude/skills/
# every projectmkdir -p ~/.claude/skills && cp -r skills/company-architect ~/.claude/skills/Then just say what you want:
Set up a Crewlet company for a 5-person dev-tools startup.
Any other assistant — Cursor, Copilot, Codex, the ChatGPT/Claude web
apps: paste the file, attach it, or add it to your rules/context
directory. If you installed Crewlet with pip and don’t have a repo
checkout, fetch it from
GitHub.
What it will do
Section titled “What it will do”- Interview you about the company before writing anything.
- Start you integration-free with one scheduled task, so you see a real agent turn within minutes — then layer integrations one at a time.
- Keep every secret as a
${VAR}reference, never a literal. - Put you in the org chart as a human seat.
- Warn you that handles are effectively permanent (see below).
- Validate after every edit, and not claim success until it passes.
What it can’t do
Section titled “What it can’t do”It writes config; it doesn’t provision. Creating the Slack apps, the
Plane workspace, the GitLab group, and the API keys is still your job —
Choosing your stack lists what you must create
by hand for each. Once those exist,
crewlet plane provision
and crewlet gitlab provision
mint the per-seat accounts and tokens into the ${VAR} references the
config already declares.
The one thing to get right before you run
Section titled “The one thing to get right before you run”Handles are effectively permanent. An agent’s durable id is
uuid5(namespace, f"{org.name}:{handle}"), so renaming a seat’s
handle — or the company name — mints a new id and orphans that
agent’s diary, onboarding markers, and counterparty profiles. The seat
keeps working, but it has lost its memory.
Settle the company name and each handle before the company runs. See Agent Runtime § Agent Definition vs Agent Instance.
Next steps
Section titled “Next steps”- Quickstart — the minimal four-seat company, by hand
- Choosing your stack — every external dependency, hosted vs self-hosted
- Configuration reference — the full field list in prose
- Configure via API — the same config
over
/config/*instead of a file
Generated from crewlet/crewlet v0.1.0 at b40ea18.