Run from source

Build Steadmesh from this repository and run the example organisation on a local kind cluster with deterministic fakes. No accounts or API keys needed.

To install a published release into your own cluster without cloning the repository, use the Quickstart instead. This page is for working on Steadmesh itself, or for trying it with no accounts at all.

This walkthrough deploys the example organisation to a local kind cluster: two human representatives and an engineering team of three. Slack and Linear are replaced by deterministic fake servers from the repository, and seats run the fake harness. That harness executes scripted commands instead of calling a model, so it needs no accounts or API keys.

Every command pins the kubectl context kind-steadmesh. Nothing here uses or changes your current kubectl context.

Prerequisites

ToolVersionNotes
Go1.27Builds the binaries, the provider and the images.
Dockerany recentDocker Desktop or Colima, running. Give it at least 4 CPUs and 8 GB of memory.
kind0.24 or laterbrew install kind. Its default CNI enforces NetworkPolicy, which the platform checks before it starts any seat.
kubectl, Helmkubectl 1.30+, Helm 3
Terraform1.5 or laterTested with 1.5.7. terraform init needs network access for the kubernetes, helm and random providers.

Run it

  1. Build the tools and binaries. This installs controller-gen and setup-envtest into ./bin, then builds every command, including the Terraform provider and orgctl.

    make tools build
  2. Create the cluster and load the images. The first image build takes a few minutes; the Claude Code image is the largest.

    make kind-up kind-load
  3. Apply the foundation stage. This creates the namespaces steadmesh-system and steadmesh-example, Postgres, and the credential Secrets. The Secrets hold placeholder values, which the fakes accept.

    make -C examples apply-foundation
  4. Start the fake Slack and Linear servers.

    kubectl --context kind-steadmesh apply -f tests/e2e/manifests/fakes.yaml
    kubectl --context kind-steadmesh -n steadmesh-system rollout status deploy/steadmesh-fakes
  5. Point the organisation at the fakes and apply everything else. make apply installs the platform chart, applies the organisation through the steadmesh provider, waits for readiness, then runs a fresh verification. Setting a 1-minute idle timeout lets you watch seats go to sleep.

    export TF_VAR_slack_endpoint_ref=http://steadmesh-fakes.steadmesh-system.svc:8090
    export TF_VAR_linear_endpoint_ref=http://steadmesh-fakes.steadmesh-system.svc:8091
    export TF_VAR_seat_idle_timeout=1m
    make -C examples apply

    The run ends with a readiness report like this:

    CONDITION                 STATUS  REASON     MESSAGE
    Configured                True    Compiled   5 seats resolved; defaults version 1
    IdentitiesReady           True    Synced     5 seat identities active
    ConnectionsAuthenticated  True    Verified   2 connection verified
    IngressReady              True    Verified   1 ingress verified
    BindingsValid             True    Verified   2 binding verified
    StorageReady              True    Ready      5 seat workspaces provisioned
    HarnessCompatible         True    Ready      harness profiles compatible
    SandboxEnforced           True    Ready      sandbox restrictions verified
    RoutesExecutable          True    Ready      ...
    OperationalReady          True    Ready      ...
    
    HUMAN  REPRESENTATIVE       CHANNEL        USER
    alex   representative_alex  slack (slack)  U0ALEX
    sean   representative_sean  slack (slack)  U0SEAN
  6. Message your representative. The fake Slack server has test endpoints that inject a direct message from a user and list what the bot posted. Forward its port, then send a message as Sean:

    kubectl --context kind-steadmesh -n steadmesh-system port-forward svc/steadmesh-fakes 8090:8090 &
    
    curl -s localhost:8090/_test/dm -d '{"user":"U0SEAN","text":"hello from sean"}'
    sleep 20   # a sleeping seat takes a few seconds to wake
    curl -s localhost:8090/_test/posted | jq -r '.[] | "\(.channel): \(.text)"'
    D0SEAN: ack: hello from sean

    That reply went from the message, through the platform's durable inbox, to Sean's representative seat, which woke up, ran a turn and replied through the outbox to Slack. No manual command was involved.

  7. Or chat from a terminal. A human can reach their representative from a terminal instead of Slack. Put Sean on the terminal connection, which generates his token in the Secret terminal-credentials, and re-apply:

    export TF_VAR_terminal_users='["sean"]'
    export TF_VAR_humans='{"sean":{"channel":"terminal","display_name":"Sean'"'"'s representative"},"alex":{"slack_user_id":"U0ALEX"}}'
    make -C examples apply
    
    bin/orgctl chat --context kind-steadmesh --user sean
    Chatting with sean's representative over terminal.
    
    you 14:02
      hello from sean
    
    representative 14:02
      ack: hello from sean
    
    › Message your representative
    enter send · alt+enter new line · ↑ history · ctrl+c quit

    orgctl chat port-forwards to the platform and reads the token from the connection's Secret; pass --token for a Vault reference. The representative's replies are rendered as markdown, in colour matched to a light or dark terminal. When input or output is not a terminal, for example when piping a message in, it falls back to plain lines. The representative can message you at any time with messages.reply. Anything it sends while no terminal is open waits in the platform's memory, up to 200 messages, and appears when you next connect. Those queued messages are lost if the platform restarts.

  8. Delegate work and create a tracker project. The fake harness runs lines that start with / as commands (see the script language). This message asks the representative to delegate to the engineering lead. The lead creates a Linear project and the result comes back to Sean:

    curl -s localhost:8090/_test/dm -d @- <<'JSON'
    {"user":"U0SEAN","text":"/delegate eng_lead /task\n/tool connections.invoke {\"connection\":\"linear\",\"operation\":\"project.create\",\"params\":{\"name\":\"Onboarding checklist\"}}"}
    JSON
    sleep 30
    curl -s localhost:8090/_test/posted | jq -r '.[-1].text'
    Update from eng_lead: task result from eng_lead:
    tool connections.invoke: {"id":"…","connection":"linear","operation":"project.create","status":"succeeded","external_receipt":"proj-…"}

    Confirm the project exists in the fake tracker:

    kubectl --context kind-steadmesh -n steadmesh-system port-forward svc/steadmesh-fakes 8091:8091 &
    curl -s localhost:8091/_test/state | jq '.projects[].name'
  9. Watch the seats. After a minute without work, seats scale to zero and keep their workspace and memory. The next message wakes them.

    make -C examples status
    kubectl --context kind-steadmesh -n steadmesh-example get agentseats -w

Clean up

make -C examples teardown   # destroy organisation, platform and foundation
make kind-down              # delete the kind cluster

The same flow, with many more checks, is automated by make e2e. That suite covers replayed events, lost API responses, Pod kills, sleeping seats, control-plane restarts and credential leaks. See Acceptance status.

Next steps