Documentation

From zero to running conspiracy in about five minutes.

Prerequisites

  • Docker or Podman
  • Go 1.22+ (both paths require building a Go binary)
  • An API key (Anthropic or OpenRouter)

The container runs Ubuntu 24.04 or Debian 12 with systemd as PID 1. Your host just needs a container runtime.

Quick Start

Build the conos CLI, then let it handle the rest.

git clone https://github.com/ConspiracyOS/conos.git
cd conos && go build -o conos ./cmd/conos/

CONOS_API_KEY is the env var that holds your LLM provider's API key (Anthropic, OpenRouter, etc.). The name is configurable via api_key_env in the config.

CONOS_API_KEY=sk-your-key-here ./conos install

This pulls the image, writes the env file, and starts the container. One command, one running system.

./conos status

Build from Source

For contributors, or if you want to modify the inner runtime.

git clone https://github.com/ConspiracyOS/conctl.git
git clone https://github.com/ConspiracyOS/container.git

# Build the inner binary
cd conctl && go build -o conctl ./cmd/conctl/ && cd ..

# Configure
cd container
cp .env.example srv/dev/container.env
# Edit srv/dev/container.env — set CONOS_API_KEY=your-key-here

# Build and deploy
make image CONCTL_BIN=../conctl/conctl
make deploy

The container boots, provisions agent users and inboxes, and starts watching for tasks. Verify with make status.

First Task

Talk to the concierge. It routes your request to the right agent.

With conos:

conos agent "What agents are running in this conspiracy?"
conos agent logs -f     # watch the audit log

With make (from the container repo):

make task MSG="What agents are running in this conspiracy?"
make logs               # tail the audit log
make responses          # check agent outboxes

The concierge reads the task from the outer inbox, picks the right agent, and routes it. Responses land in agent outboxes.

To task a specific agent directly:

conos agent task sysadmin "Run the contracts"

How Tasks Flow

A conspiracy has one entry point: the outer inbox (/srv/conos/inbox/). When you run conos agent "do something", the CLI writes a .task file into that directory. A systemd path unit detects the new file and wakes the concierge.

The concierge reads the task, decides which agent should handle it, and moves the file to that agent's inbox (/srv/conos/agents/<name>/inbox/). Another systemd path unit detects it and starts the agent's service. The agent reads the task, does the work, and writes a response to its outbox.

There is no message bus, no RPC layer, no internal API. Agents communicate by writing files. Routing is file-move. Activation is systemd. The entire coordination layer is filesystem + init system.

Tiers

Tiers control privilege, not intelligence. Every agent runs the same kind of LLM — tiers determine what the OS allows it to do.

TierCan TaskHardening
Officer Any agent NoNewPrivileges, ProtectSystem=strict
Operator Any agent NoNewPrivileges, ProtectSystem=strict, ReadWritePaths scoped
Worker Nobody All of the above + BindReadOnlyPaths, PrivateTmp, ProtectHome=tmpfs

Officers set policy (the strategist reviews system state daily and writes standing orders). Operators execute (the concierge routes tasks, the sysadmin commissions agents). Workers do a single job and write a response. They cannot task other agents — the kernel blocks writes to other inboxes via POSIX ACLs.

Skills & Roles

An agent's behavior is defined by two things: instructions and skills.

Instructions (AGENTS.md) define identity, constraints, and decision-making rules. They tell the agent what it is and what to consider when working.

Skills are step-by-step procedures for specific tasks. They live in /etc/conos/roles/<role>/skills/*.md and are injected into the agent's prompt at task time. Skills tell the agent how to do things — exact commands, verification steps, and checklists.

/etc/conos/
  roles/
    sysadmin/
      skills/
        commission-agent.md    # 11-step procedure for creating an agent
        evaluate-request.md    # decision tree for evaluating requests
        writing-contracts.md   # how to write detective contracts
        heartbeat-audit.md     # interpret healthcheck results
  agents/
    concierge/
      AGENTS.md                # concierge identity and routing rules
    sysadmin/
      AGENTS.md                # sysadmin identity and constraints

Agents reference roles in the config (roles = ["sysadmin"]). At task time, skills from those roles are copied to the agent's workspace and injected into the prompt. The agent is told: "If a skill exists for what you are doing, use it. Do not improvise."

Skills and agent instructions are owned by root and set immutable (chattr +i). An agent cannot modify its own instructions or skill files — the kernel prevents it.

Configuration

Everything lives in conos.toml. The default config ships with three agents: concierge, sysadmin, and strategist.

[system]
name = "my-conspiracy"

[dashboard]
enabled = true
port = 8080

[contracts]
brief_output = "/srv/conos/context/system-state.md"

[base]
runner = "picoclaw"
provider = "anthropic"
api_key_env = "CONOS_API_KEY"     # env var holding your LLM provider key

[base.officer]
model = "claude-sonnet-4-6"

[base.operator]
model = "claude-sonnet-4-6"

The [base] section sets defaults. [base.officer] and [base.operator] override per tier. Individual agents inherit from their tier unless they specify their own model or provider.

Adding an Agent

Append to conos.toml:

[[agents]]
name = "researcher"
tier = "worker"
mode = "on-demand"
packages = ["curl", "jq"]
instructions = """
You are the Researcher. You gather information from
approved sources and summarize findings.
"""

Redeploy to provision the new agent:

conos config apply    # if using conos
make deploy           # if building from source

Bootstrap creates the Linux user (a-researcher), home directory, inbox, outbox, workspace, systemd units, and ACLs. It installs any declared packages and deploys skills from the agent's roles. The agent exists because Linux says it does.

Agent Fields

FieldRequiredDescription
nameyesAgent name. Becomes Linux user a-<name>.
tieryesofficer, operator, or worker.
modeyeson-demand (inbox-triggered), cron, or continuous.
instructionsyesSystem prompt. Injected at task time.
rolesnoList of roles. Loads skills from /etc/conos/roles/<role>/skills/.
packagesnoApt packages installed on bootstrap. Also installable at runtime.
cronnoCron expression. Required if mode = "cron".
runnernoOverride runtime binary (default: inherited from [base]).
runner_argsnoArguments for the runtime binary.

Packages

Agents sometimes need tools — psql for database queries, curl for HTTP, jq for JSON processing. Packages declared in the config are installed at bootstrap:

[[agents]]
name = "data-analyst"
packages = ["postgresql-client", "jq"]

For runtime installation without restarting:

# Install now (ephemeral — lost on container restart)
conctl package install postgresql-client --agent data-analyst

# Install and persist to conos.toml
conctl package install postgresql-client --agent data-analyst --save

The --save flag writes the package to the config so it survives restarts. Without it, the install is immediate but ephemeral.

Package installation goes through conctl package, not raw apt-get. This validates the package name, logs the action to the audit trail, and keeps apt-get out of agent sudoers.

Contracts

Contracts are YAML-defined checks that assert the system matches its intended state. They run on systemd timers (typically every 60 seconds) and report pass, fail, or warn for each check.

Prevention is the OS's job — chmod, nftables, sudoers enforce boundaries at the kernel level. Detection is the contract's job — contracts verify that those preventive controls stayed in place. If an ACL was loosened, a file permission changed, or a service stopped, the contract catches it.

There are three contract types:

  • Detective — runs on a timer, detects drift. Most contracts are this type.
  • Atomic — single-state assertion. Semantically identical to detective.
  • Protocol — runs before a destructive action, enforces preconditions. See below.

The contracts framework is standalone. It runs on any Linux system — no dependency on the rest of ConspiracyOS.

Writing Contracts

A contract is a YAML file in /srv/conos/contracts/:

id: CON-SEC-001
description: Skill files must be owned by root
type: detective
tags: [schedule]
scope: global
checks:
  - name: skills_root_owned
    script:
      inline: |
        found=$(find /etc/conos/roles -name '*.md' ! -user root)
        [ -z "$found" ]
    on_fail: escalate
    severity: critical
    category: security
    what: "Skill files not owned by root"
    verify: "find /etc/conos/roles -name '*.md' ! -user root"
    affects: ["/etc/conos/roles"]

Key fields:

FieldPurpose
idUnique ID. Convention: CON-{SEC|SYS|AGENT}-NNN
typedetective, atomic, or protocol
tags[schedule] to run on the healthcheck timer
on_failAction on failure: alert, escalate, halt_agents, halt
severitycritical, high, medium, low
whatHuman-readable finding (shown in reports)
verifyCommand to manually verify the issue
affectsPaths or resources affected

Check types: command (single command + exit code), script (inline or file), regex_in_file, path_exists, yaml_key/json_key/toml_key, env_var, command_available. A check passes when exit code is 0 or the assertion holds.

Protocol Contracts

Protocol contracts are precondition gates. They don't run on a timer — they run explicitly before a destructive action.

id: CON-PROTO-001
description: Preconditions before disabling Tailscale
type: protocol
trigger: "tailscale down"
checks:
  - name: lan_ssh_reachable
    command:
      run: "ssh -o ConnectTimeout=5 -o BatchMode=yes nas 'echo ok'"
      exit_code: 0
    on_fail: halt
    severity: critical
    what: "LAN SSH unreachable — disabling Tailscale would lock out the host"

Run a protocol check before acting:

# Check preconditions (exit 0 = clear, exit 1 = blocked)
conctl protocol check CON-PROTO-001

# Override a specific check with a reason
conctl protocol check CON-PROTO-001 --exempt lan_ssh_reachable \
  --reason "Physical console access confirmed"

Exemptions are logged to the audit trail. Detective contracts can later verify whether the exemption was justified.

Built-in Contracts

The default config ships with 15 contracts across three categories:

IDWhat it checksOn failure
CON-AGENT-001Agent directories have correct permissions/ownershipalert
CON-AGENT-002Agent instructions (AGENTS.md) are root-owned, read-onlyalert
CON-SEC-001Skill files owned by rootescalate
CON-SEC-002Agent git repos have no unauthorized remotesalert
CON-SEC-003Exposed artifacts have valid manifestsalert
CON-SEC-004Artifacts don't contain secretsescalate
CON-SEC-005Critical files have immutable bit setescalate
CON-SYS-001Disk free ≥ 15%halt_agents
CON-SYS-002Memory available ≥ 10%halt_agents
CON-SYS-003Load average ≤ 2x CPU coreshalt_agents
CON-SYS-004No agent session exceeds 30 minutesalert
CON-SYS-005Audit log directory is writablehalt_agents
CON-SYS-006/etc/conos/env is mode 600 root:rootalert
CON-SYS-007auditd service is activealert
CON-SYS-008System state snapshot + change diffalert

Security Model

Three layers, each independent:

  1. Prevention — the OS enforces boundaries. File permissions (chmod 700), POSIX ACLs on inboxes, nftables per-uid firewall rules, and sudoers allowlists. A compromised agent cannot bypass these because they are enforced by the kernel, not the application.
  2. Immediate detectionauditd watches on critical directories generate events the instant a write is attempted. Combined with immutable files, the write fails but is always logged.
  3. Periodic verification — detective contracts run every 60 seconds. They verify that preventive controls stayed in place and that system state matches intent. This is the safety net that catches anything the first two layers missed.

The design assumption is that every agent will eventually process adversarial input. A fully compromised agent should accomplish nothing beyond its intended capability.

Trust Boundaries

Trust is determined by provenance (file ownership), not content:

  • User input (outer inbox) — trusted. The user has machine access.
  • Agent-routed tasks — semi-trusted. The routing agent may have been influenced by external content. Agents see [trust:verified] or [trust:unverified] in the task header.
  • External data (email, URLs, APIs) — untrusted. Agents are instructed not to take consequential actions based on unverified input.

Provenance is checked via lstat() on the task file. Files owned by root or a member of the trusted group are verified. Agent-owned files are unverified. Symlinks are always treated as unverified regardless of target ownership.

Immutable Files

Critical configuration files are set immutable with chattr +i during bootstrap. Even root cannot modify them without first removing the immutable flag — which requires CAP_LINUX_IMMUTABLE. No agent has this capability.

Immutable files:

  • /etc/conos/conos.toml — config
  • /etc/conos/env — API keys
  • /etc/conos/roles/*/skills/*.md — skill files
  • /etc/conos/agents/*/AGENTS.md — agent instructions
  • /etc/conos/contracts/*.yaml — contract definitions
  • /etc/sudoers.d/conos-* — sudoers rules
  • /etc/systemd/system/conos-* — systemd units
  • /usr/local/bin/conctl — the binary itself

Legitimate changes go through conctl (e.g., conctl config apply, conctl bootstrap), which temporarily removes the immutable bit, makes the change, and re-applies it. The sysadmin agent has no sudoers entry for chattr — it can only go through the controlled conctl path.

Drivers

A driver connects an external interface to the conspiracy. It receives messages from a platform, forwards them as tasks via SSH, polls for responses, and pushes them back. Drivers are standalone Go binaries that run on any host with SSH access to the container.

Discord

Receives Discord messages, forwards to the concierge, posts responses back to the channel or DM.

cd conos/drivers/discord
export DISCORD_BOT_TOKEN="..."
export DISCORD_CHANNEL_ID="..."       # omit for DM mode
export CONOS_SSH_HOST="your-instance"
go build . && ./discord

Supports slash commands: /status, /logs, /responses, /clear (reset session history). Artifact links are resolved to signed URLs. Secrets are redacted from responses before posting.

OpenClaw

Receives webhooks from the OpenClaw Gateway, which bridges WhatsApp, Telegram, Slack, and other messaging platforms.

cd conos/drivers/openclaw
export OPENCLAW_HOOK_TOKEN="your-secret"
export OPENCLAW_GATEWAY_URL="http://your-gateway:18789"
export CONOS_SSH_HOST="your-instance"
go build . && ./openclaw

Configure the Gateway to POST to http://<driver-host>:3847/webhook?token=<OPENCLAW_HOOK_TOKEN>. Messages flow: user's app → Gateway → webhook → SSH task → concierge → agent → response poll → Gateway API → user's app.

conos (host-side)

conos install                        # pull image, create env, start
conos start                          # boot the instance
conos stop [--force]                 # stop the instance
conos status                         # agent status overview
conos config apply                   # push config into running instance

conos agent list                     # list agents
conos agent <message>                # task the concierge
conos agent task <name> <message>    # task a specific agent
conos agent logs [-f] [-n N] [name]  # tail audit log
conos agent kill <name>              # stop a running agent

conctl (inside the container)

You rarely need these directly. They are what conos calls over SSH.

# Operations
conctl bootstrap                     # provision the conspiracy from config
conctl run <agent>                   # execute one task cycle for an agent
conctl status                        # agent status
conctl logs [-f] [-n N] [agent]      # audit log
conctl task [--agent <name>] <msg>   # drop a task into an inbox
conctl kill <agent>                  # stop agent systemd units
conctl clear-sessions [agent]        # wipe PicoClaw session history

# Contracts
conctl healthcheck                   # evaluate all contracts
conctl doctor                        # system verification report
conctl brief                         # system state summary for agents
conctl manifest show                 # dump expected system state as YAML

# Protocol contracts
conctl protocol check <id> [--exempt <check> --reason <reason>]
conctl protocol list                 # list protocol contracts

# Package management
conctl package install <pkg> --agent <name> [--save]
conctl package remove <pkg> --agent <name> [--save]
conctl package list [--agent <name>]

# Artifacts
conctl artifact create|show|link|verify
conctl task-contract open|claim|update|show

make targets (from the container repo)

make image          # build the container image
make deploy         # build + restart
make run            # start the container
make stop           # stop the container
make status         # agent health and last activity
make logs           # tail audit log
make responses      # latest response from each agent
make task MSG="..." # send a task to the concierge

Inspecting a Running System

SSH into the container or use docker exec:

docker exec -it conos bash

Useful things to look at:

# Config
cat /etc/conos/conos.toml

# Agent home directories
ls /srv/conos/agents/

# Inboxes (where tasks land)
ls /srv/conos/agents/*/inbox/

# Outboxes (where responses appear)
ls /srv/conos/agents/*/outbox/

# Who can write to an inbox
getfacl /srv/conos/agents/sysadmin/inbox/

# Audit log
journalctl -u "conos-*" --no-pager -n 50

# Contract results
conctl doctor

# System state brief (what agents see)
cat /srv/conos/context/system-state.md

# Who owns what
stat /srv/conos/agents/concierge/

# Check immutable flags
lsattr /etc/conos/conos.toml /usr/local/bin/conctl

Every agent is a Linux user. Every inbox is a directory. Every permission boundary is a file mode. There is no abstraction layer to debug — just the OS.

Troubleshooting

Agent not responding to tasks

# Is the inbox watcher running?
systemctl status conos-concierge.path

# Is the service failing?
journalctl -u conos-concierge.service -n 20

# Is there a task stuck in the inbox?
ls -la /srv/conos/agents/concierge/inbox/

# Is the agent's session oversized? Clear it.
conctl clear-sessions concierge

Contract keeps failing

# See the full report
conctl doctor

# Run the check manually using the verify command from the contract
find /etc/conos/roles -name '*.md' ! -user root

# Check if immutable bit was stripped
lsattr /etc/conos/conos.toml

Bootstrap fails

# Check the bootstrap log
journalctl -u conos-bootstrap.service --no-pager

# Re-run bootstrap manually
conctl bootstrap

# Verify expected state vs actual state
conctl doctor

"Permission denied" errors

# Check who owns the file
stat /path/to/file

# Check ACLs
getfacl /path/to/directory

# Check what the agent's sudoers allows
cat /etc/sudoers.d/conos-sysadmin