Local development
This guide brings the full TruStacks platform up on a local Kubernetes cluster from source: k3d running on your laptop, Gitea as the in-cluster Git server, ArgoCD watching a sample platform repo, Zot as the OCI registry for signed policy bundles, the Control Plane, the Runner, and the UI.
The intended audience is contributors with trustacks-mvp
repository access who want to build TruStacks from source and iterate
on it. For evaluators and workshop attendees, the
quickstart is the right path; it pulls
signed images from ghcr.io/trustacks/* and doesn’t need repository
access.
Scoped to contributor development. The procedure on this page builds images locally and runs against the source tree. Customer production installation is moving to the Cluster Operator (post-Beta); for production deploys today, see the cluster install guide.
What gets installed
After bring-up, the following services are running in your k3d cluster,
all reachable via Traefik on *.localtest.me:8080:
| Service | URL | Purpose |
|---|---|---|
| UI | http://ui.localtest.me:8080 | Chat-first product surface |
| Control Plane | http://cp.localtest.me:8080 | API + audit + SSE event stream |
| Runner | http://runner.localtest.me:8080/healthz | The agent crew lives here |
| Gitea | http://gitea.localtest.me:8080 | In-cluster Git server (replaces GitHub for local) |
| Argo CD | http://argocd.localtest.me:8080 | GitOps controller watching the platform repo |
| Zot | http://zot.localtest.me:8080/v2/ | OCI registry for signed policy bundles |
localtest.me resolves to 127.0.0.1 automatically. No /etc/hosts
edits required.
Prerequisites
You need a Mac or Linux box with Docker and a small set of CLIs.
Required tools
On macOS, install with Homebrew:
brew install --cask docker # Docker Desktop, then start it
brew install k3d helm kubectl uv node opa orasMinimum versions:
- k3d ≥ 5.8
- helm ≥ 3.14
- kubectl (latest)
- uv (Python toolchain manager)
- node ≥ 20 + npm
- opa ≥ 1.x (Open Policy Agent CLI; runs Rego tests + builds bundles)
- oras ≥ 1.3 (pushes the policy bundle to the in-cluster Zot registry)
On Linux, install the equivalents through your package manager or each project’s release binaries.
Anthropic API key
The Runner needs an Anthropic API key to talk to Claude. Get one at console.anthropic.com . OpenRouter is supported as a BYO escape hatch; both providers route to Claude Sonnet 4.5+.
Source
Clone the TruStacks repository (you need access to
github.com/TruStacks/trustacks-mvp while it is in private Beta).
git clone https://github.com/TruStacks/trustacks-mvp.git
cd trustacks-mvpBring-up
The full bring-up takes four commands plus one verification step.
1. Configure your environment
cp .env.example .env
# edit .env, set ANTHROPIC_API_KEY=<your-key>The Runner will not start without an Anthropic key. If .env is missing
or ANTHROPIC_API_KEY is empty, make up fails at the secrets step.
The cluster is still up after that failure; rerun make secrets once
the key is set to recover.
2. Install language dependencies
make installInstalls Python virtualenvs via uv for the Control Plane and Runner,
plus node_modules for the UI.
3. Bring up the cluster
make upThis is the slow one. It creates the k3d cluster, installs Traefik as the ingress, deploys Gitea + ArgoCD + Zot, then deploys the Control Plane, the Runner, and the UI. The last step applies your Anthropic key to the Runner’s Secret.
Verify with make doctor if any step looks wrong.
4. Seed the demo data
make seedmake seed is the single demo-bootstrap command. It is idempotent; you
can re-run it any time. Order of operations:
- Apply the cosign public key as a ConfigMap so the Runner’s init container can verify policy bundles before extract.
- Build and push the constitution bundle:
opa build -b policy/constitution, push to Zot viaoras, sign with cosign. The Runner’s init container pulls the bundle, runscosign verify, and extracts only on a clean verify. - Seed Gitea with the seven demo repositories: four polyglot
service samples (
sample-appfor FastAPI,sample-app-spring-bootfor Spring Boot,sample-app-dotnetfor .NET,sample-app-gofor Go) plus the platform and overlay infra repos. - Provision deploy keys: per-repo SSH ed25519 keys, registered with Gitea and applied as labeled K8s Secrets the Runner’s init container picks up dynamically. Plus a Gitea API token for opening PRs.
- Seed connection profiles in the Control Plane for each seeded repo.
- Apply the ArgoCD root: an Application that watches
argocd/*.yamlin the platform repo. Anything the DevOps Engineer ships intoargocd/becomes a child Application after merge. - Roll the Runner so its init containers pick up the new deploy keys and the freshly-signed bundle.
5. Confirm everything is reachable
make urlsPrints the URL + credentials table for every service, including the live ArgoCD admin password.
Run your first analysis
The platform delivers two flows: the Code Reviewer (repo discovery to structured analysis) and the DevOps Engineer (analysis + Environment Profile to a PR opened against the platform repo).
Code Reviewer
cd runner && uv sync # one-time
uv run trustacks review sample-app-gitea # streams events liveEvent sequence: started → cloned → tool_call / tool_result / finding ×N → done. The terminal done event’s payload is the final
RepositoryAnalysis. The CLI prints the analysis ID at the top. Copy
it for the next step.
DevOps Engineer
A Proposal is built from a specific prior Analysis. Pass the analysis ID:
uv run trustacks plan <analysis-id> # opens a PR on platform
uv run trustacks plan <analysis-id> --dry-run # preview, no PRtrustacks plan chains six stages:
- Clone the customer’s app repo at the analysis-time ref.
- Emit a
stale_analysiswarning if HEAD has moved. - Clone the overlay repo and load the Environment Profile.
- Run the DevOps Engineer agent. It emits a CI workflow, a Helm chart, and an ArgoCD Application.
- OPA policy gate. The Runner shells
opa evalagainst the OCI-pulled constitution. On allow, continue. On deny, emitpolicy_checkwith violations and short-circuit (no PR, nodone). - Push to a
trustacks/<id>branch on the platform repo and open the PR via Gitea’s API.
--dry-run swaps the writer step for dry_run_skipped. The proposal
is rendered locally and in the UI, but no branch is pushed.
Watch it in the UI
Open http://ui.localtest.me:8080. The sidebar surfaces Activity /
Applications / Services / Gaps / Rules / Settings. Click into your
service and you will see the analyses and proposals tabs, with the live
event log mirroring what the CLI streamed. Proposals show:
- A green
✓ policy cleanline, or a red✗ policy denywith rule IDs. - A green Pull request opened banner with the PR URL on success.
- An amber Dry run banner if the writer was skipped.
Connect your own repo
Once the demo loop is closed, you can connect a real repository through the UI’s + Connect repo wizard. The wizard supports two providers:
- Gitea path · for already-existing repos on the in-cluster Gitea. Generates an ed25519 keypair, registers the public key, applies the Secret, registers the connection profile, and rolls the Runner.
- GitHub path · for repos on github.com. Fetches the App install URL from the Control Plane, redirects you to GitHub, and after you install the TruStacks App on a repo, redirects back with the installation ID. Requires one-time operator setup of the TruStacks GitHub App. Until that is done, the wizard’s GitHub branch shows an amber “ask your admin” state.
GitLab and Azure DevOps providers ship post-Beta.
Common operations
Tear down
make downDeletes the k3d cluster entirely. Re-running make up then make seed
brings everything back.
Rotate the LLM key
Two paths. Prefer the UI when the Control Plane is up:
- UI path · open
http://ui.localtest.me:8080/#/settings/llm. Paste the new key, confirm, save. The Control Plane runs a live ping against the provider, rewrites thetrustacks-runner-llmSecret, and rolls the Runner. .env+ make path · for fresh-cluster bootstrap before the Control Plane is up. UpdateANTHROPIC_API_KEYin.env, thenmake secrets.
Re-seed after a roll
A few things are stored ephemerally in the local cluster.
- The Control Plane’s SQLite is in an
emptyDir. A CP pod restart wipes proposals, analyses, and connection profiles. Re-runmake seed. - Gitea has
persistence.enabled=false. Anyhelm upgradeagainst the Gitea release wipes its database.make seedis idempotent; roll the Runner once afterward so the new Secrets are mounted. - Zot also runs without persistence.
make seedre-pushes the constitution. The Runner falls back to the image-baked bundle (/etc/trustacks/policy/) if Zot is unreachable, so the cluster stays functional during a Zot wipe.
Re-seed after a policy update
After editing rules under policy/constitution/, re-run make seed or
just make policy-bundle to push the freshly-built bundle to Zot.
Otherwise the Runner keeps verifying and extracting the previously-tagged
bundle.
Troubleshooting
make up fails at the secrets step
ANTHROPIC_API_KEY is missing or empty in .env. The cluster is still
up; set the key and run make secrets.
git@gitea-ssh: Permission denied after a Gitea wipe
The deploy keys in Gitea are out of sync with the Secrets in
trustacks-system. Re-run make seed, then roll the Runner.
UI /rules page is empty
The constitution bundle has not been pushed to Zot yet (the page reads
its rule inventory from inside the bundle). Run make policy-bundle or
the full make seed.
Policy check denies your first proposal
This is the system working as designed. The constitution rejected your
proposal. The policy_check event payload includes the rule IDs that
denied. See the constitution reference for
what each rule checks.
Where to go next
- Credentials and secrets · the four-secrets pattern the Runner needs
- GitOps integration · how ArgoCD picks up the PRs the DevOps Engineer ships
- Quickstart · the customer workshop
path:
curl | bash, signed images, no repository access required - Policy authoring workshop · write your first overlay rule