Quickstart
Hosted TruStacks takes about 30 minutes to set up. You create a workspace at app.trustacks.com, install one runner in a Kubernetes cluster you control, connect a service repo and a platform repo, and the agent crew opens a policy-checked pull request in your platform repo. You review and merge it, and your own ArgoCD deploys it.
Agents propose. Policy decides. Humans approve.
This page follows the in-app Get set up wizard in the same order, then continues past it to the steps the wizard does not cover: the caller workflow in your service repo, ArgoCD, and what happens after the first deploy.
Beta. Everything on this page works on the hosted service today. Where a step is new, partial, or has a known sharp edge, it is called out inline and collected under Beta limits. Nothing here should be read as more finished than that.
What you need
- A Kubernetes cluster you control, version 1.28 or newer. A laptop
cluster (Docker Desktop, k3d, kind) is fine for a first run. The runner image
is published for
amd64andarm64. kubectlpointed at that cluster, andhelm3.14 or newer.- A GitHub account or organization where you can install a GitHub App.
- Two repos in it:
- a service repo: the application code you want delivered;
- a platform repo: your GitOps repo, where TruStacks opens pull requests. An empty repo is a fine starting point.
- An Anthropic API key, or an OpenRouter key. You paste it in step 7.
- The GitHub CLI (
gh), for one access grant in step 10. You can do the same thing in GitHub’s settings instead. - ArgoCD in a cluster, if you want step 11 (deploy). Steps 1 to 10 do not need it.
Step 1. Create your workspace
Go to app.trustacks.com
and click Sign in. That takes you to the TruStacks sign-in page at
auth.trustacks.com. Choose Register and create your organization and
user (email and password).
Start from app.trustacks.com, not from auth.trustacks.com directly, so the sign-in redirects you back into the app when you finish.
Registering creates a new, isolated workspace with a 30-day trial, and makes you its owner. You land on Get set up.
Adding teammates. Invite colleagues from Team in the sidebar. They get an email and join your workspace. A teammate who registers on their own creates a separate workspace instead. During Beta every member is an owner. See the Team guide.
Card-based signup. The app also has a Create a workspace path that starts a trial through card checkout. It is shown only when self-serve billing is enabled. Until then it says self-serve signup isn’t open yet; use Register as described above.
Step 2. Tell us about your team (optional)
The first wizard step is a short team profile. It helps us tailor support and does not gate anything. Skip it if you like; you can fill it in later.
This is not the Environment Profile in step 6. This one is who you are; that one is what you run.
Step 3. Enroll your runner
The runner is the only TruStacks component you install. It runs in your cluster, calls out to the hosted control plane over HTTPS, and does all the work that touches your code. Nothing connects inbound to your cluster.
-
In the wizard (or Runners in the sidebar), click Generate enrollment token. The UI shows the token and a ready-made
helm installcommand with the token already in it. -
Copy the command from the UI. It pins the chart version the control plane currently publishes, so you always install a release we have tested against the hosted service. The commands on this page use a shell variable for the namespace; set it once to the namespace you want the runner in:
NAMESPACE=trustacks-system # any namespace you chooseThe UI’s command has this shape, with the version and token filled in:
VERSION=0.0.0 # placeholder: the UI fills in the published version TOKEN=paste-from-ui # placeholder: the enrollment token the UI shows helm install trustacks-runner oci://ghcr.io/trustacks/charts/runner \ --version "$VERSION" \ -n "$NAMESPACE" --create-namespace \ --set saas.enrollmentToken="$TOKEN"The chart is a public OCI artifact; no registry login is needed. The hosted control plane URL is already set in the published chart, so the token is the only value you supply.
-
Wait for it to come up:
kubectl -n "$NAMESPACE" rollout status deploy/trustacks-runner-runner kubectl -n "$NAMESPACE" logs deploy/trustacks-runner-runner | grep -i enrollWith the release name
trustacks-runner, the deployment is namedtrustacks-runner-runner(the chart appends-runner). -
The wizard shows Runner connected a few seconds after the runner enrolls, and moves on.
The enrollment token is reusable and does not expire. It is stored only as a hash on our side, and the runner keeps presenting it when it re-enrolls, so keep it, and protect it like a password: anyone holding it can enroll a runner into your workspace. Generate another to enroll a second runner. The token ends up in a Secret in your namespace; to supply it from a Secret you manage instead, see the runner install reference.
Verify before you run it. The chart, the runner image, and the policy
bundle are all signed keylessly with Sigstore. Your security team can check
them with cosign verify before anything starts. See
Runner install.
Step 4. Create an Application
An Application is the unit TruStacks works in: one or more service repos plus the one platform repo their delivery config lands in. Every service repo belongs to exactly one Application, so you create the Application first. The connect wizard refuses to run until one exists.
- In the wizard’s Connect a repo step, give your first Application a name and click Create application. Names are lowercase letters, numbers, and hyphens (they become Kubernetes names and a directory in your platform repo), and cannot be changed later.
- Open it from Applications and check two settings on the detail page:
- Target clusters. Every Application needs at least one cluster with a
tier (
dev,uat, orprod). A new Application starts with onedevcluster calledlocal-k3d. Rename it to the cluster name you will deploy to; the name shows up in paths in your platform repo. - Renderer. Helm (the default) or Kustomize. Kustomize support is Beta. See the Applications guide.
- Target clusters. Every Application needs at least one cluster with a
tier (
Step 5. Connect your repos
TruStacks reads your service repo and opens pull requests in your platform repo. It never writes generated files into your application code. You connect each repo once.
- Go to Services and click + Connect repo.
- Pick the role: Service (code to analyze) or Platform (where PRs land).
- Pick GitHub, then Install on GitHub. That installs the shared TruStacks GitHub App on your account or organization. Grant it access to both repos. You do not register an App of your own.
- Back in TruStacks, pick the repo, the Application from step 4, and a name.
- Repeat for the other repo with the other role.
What the GitHub App can do. It asks for Contents (read and write), Workflows (read and write), Pull requests, and Metadata, on the repos you grant it. The service role being “read-only” is enforced by TruStacks, not by a narrower GitHub permission. Agents are built to open pull requests on branches and never push to your default branch, but GitHub does not enforce that for an App with Contents write. To enforce it, protect the default branch (branch protection or a ruleset) and leave the TruStacks GitHub App out of the bypass list. Details in Credentials and trust boundary.
A service is a whole repo. If you have a monorepo, connect it as one service for now; per-path services inside one repo are not supported yet.
Step 6. Declare what you run
Commit a file named environment-profile.yaml to the root of your
platform repo. It declares the tools you already run, by category. Every
agent reads it before proposing anything, and your maturity score is computed
from it. TruStacks reads it from the platform repo through the GitHub App.
The wizard shows a starter file you can copy. A minimal one:
schema_version: "1"
name: default
ci_cd_platform:
- provider: github_actions
primary: true
gitops_controller:
- provider: argocd
primary: true
# Add one block per category you run, for example:
# image_scanning:
# - provider: trivy
# primary: true
# practices:
# tests_in_ci: trueTwo things to know:
- A category you leave out counts as a gap. It is not neutral, so your score understates what you run until you declare it.
practicesare claims about you. The starter ships every one of them commented out on purpose. Uncomment a line only when it is true; the maturity score counts it. TruStacks never fills these in for you.
The full schema is in the Environment Profile reference. Stack in the sidebar shows what TruStacks read from your file.
Step 7. Set your LLM provider
Open Settings and the LLM provider section, choose Anthropic or OpenRouter, paste your key, and save.
- The key is validated with a live call before it is accepted.
- The control plane does not store it. It holds the key in memory just long enough to seal it to your runner’s public key; your runner unseals it and writes its own Secret in your namespace.
- Agents run on Claude Sonnet 4.5 or newer. With OpenRouter the model must be
an
anthropic/model. There is no model picker; you choose who bills you, not which model runs.
See LLM provider.
Step 8. Run your first analysis
From the wizard, go to your services, open the service, and click Run analysis. Your runner picks the job up, clones the repo inside your cluster, and the Code Reviewer produces a structured analysis: framework, language, runtime, tests, and findings. You watch it stream live.
Only the Code Reviewer runs here. That is expected: the DevOps Engineer runs in the next step, and the Baseline Security and SOC2 specialists run on gap analyses.
Step 9. Promote to proposal
On the finished analysis, click Promote to proposal. The DevOps Engineer reads the analysis, your Environment Profile, and your platform repo, then writes the delivery artifacts into the platform repo: a reusable CI workflow, a Helm chart (or Kustomize base), and an ArgoCD Application.
Before anything reaches GitHub, the proposal goes through three checks, all visible on the proposal page:
- Artifact validation. The chart is rendered (
helm templateorkustomize build), the workflow is parsed, and names are checked. A check that could not run counts as a failure, not a pass. - The policy gate. The proposal is evaluated against the signed constitution. A deny stops it here; no pull request opens, and the page names the rules that denied.
- An advisory gap check against your Environment Profile. It reports; it never blocks.
On allow, a pull request opens in your platform repo. Its body explains what was generated, which rules it was checked against, and anything the agent deliberately kept from your existing repo (preservation notes). See the proposal lifecycle.
Step 10. Merge, then add the caller workflow
Review the pull request like any other change and merge it when you are satisfied. The merge is yours; no agent can do it.
Then do the one step that most often breaks a first run. The CI workflow
TruStacks wrote lives in the platform repo as a reusable workflow
(on: workflow_call). It does not run by itself. Your service repo calls
it, so the build runs against your service code.
Add a caller workflow to the service repo, once:
# .github/workflows/ci.yaml in the SERVICE repo.
# GitHub only reads workflows from .github/workflows/.
name: ci
on:
push:
branches: [main] # your default branch
pull_request:
jobs:
trustacks:
# The called workflow pushes an image. Pull requests from forks get a
# read-only token and cannot push, so skip them instead of failing.
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
uses: <owner>/<platform-repo>/.github/workflows/ci-<service>.yaml@<commit-sha>
permissions:
contents: read
packages: writeReplace the four placeholders: <owner> and <platform-repo> name your
platform repo, ci-<service>.yaml is the workflow the pull request added
under .github/workflows/ there (one per service), and <commit-sha> is the
full SHA of the platform-repo commit you want to run, for example the merge
commit of that pull request.
Pin to a commit SHA. The called workflow runs with packages: write.
Pinned, a later change on the platform repo’s main does not reach your
service’s CI until you move the pin, so when you merge a TruStacks pull
request that changes this workflow, update the SHA in the same review.
@main also works and picks up every merged change on its own, at the cost
of trusting whoever can push to that branch. The proposal summary shows this
snippet with @main and on: [push, pull_request]; use the pinned form above.
If your platform repo is private, grant Actions access once. A private
repo shares its reusable workflows with nothing by default, and GitHub reports
that as workflow was not found (naming your generated file), not as a
permissions error.
PLATFORM_REPO=your-org/your-platform-repo # owner/name of your platform repo
# Platform repo owned by an organization:
gh api --method PUT \
"repos/$PLATFORM_REPO/actions/permissions/access" \
-f access_level=organization
# Platform repo owned by a personal account:
gh api --method PUT \
"repos/$PLATFORM_REPO/actions/permissions/access" \
-f access_level=userThe same setting is in the platform repo under Settings → Actions → General → Access. Public platform repos need nothing.
Push the caller workflow. The run checks out your service, runs its tests and
lint, builds the image from the Dockerfile at the root of your service repo,
and pushes it to GitHub Container Registry tagged with the commit SHA.
TruStacks never writes to your service repo, so if it has no Dockerfile, add
one yourself.
Image visibility. A GHCR package pushed from a private repo is private.
Your cluster then needs an image pull secret for ghcr.io, or you make the
package public in its GitHub package settings. Without one of the two, the
deploy in step 11 sits in ImagePullBackOff.
Step 11. Deploy with your ArgoCD
TruStacks writes ArgoCD Applications into argo-apps/ in your platform repo.
Your ArgoCD deploys them. TruStacks does not install or operate ArgoCD.
- Give ArgoCD read access to the platform repo (a deploy key or token, set up the way you normally add a private repo to ArgoCD).
- Apply one root Application that watches
argo-apps/in the platform repo. An example is in GitOps integration. - After the next sync, ArgoCD creates an Application per service and cluster.
Emitted Applications use manual sync. Merging a pull request does not
deploy anything by itself; someone clicks Sync in ArgoCD (or runs
argocd app sync). For a target cluster with tier prod, whatever it is
named, the constitution also enforces it: a proposal that sets automated
sync on that cluster’s Application is denied. If you want automated sync on dev,
that is your change to make and review.
What happens next
Once the loop is running, these happen without another setup step:
- Image tag promotion. When your service repo’s default branch moves, the hosted control plane notices and your runner opens a pull request in the platform repo that bumps the image tag. You approve it like any other proposal. A deployed tag that lags the newest commit means the bump is waiting for review, which is the process working. The first deploy goes through this too: the commit that adds the caller workflow produces the first real image, and the tag bump that follows points at it.
- Gap analysis. Run
/gapsin Workspace, or start one from Gap analyses. The Coordinator consults the Baseline Security and SOC2 specialists and reports what is missing against your Environment Profile. Any gap can be turned into a proposal. See the Gap analyses guide. - Maturity. Maturity shows a bronze, silver, or gold tier per Application, row by row, and separates what TruStacks has verified from what you have only claimed. See Maturity scoring.
- Deploy status (optional, Beta). Install the runner with
--set observer.enabled=true --set observer.argocdNamespace=argocdand it reports ArgoCD sync and health back, read-only (get, list, and watch on ArgoCD Applications in that namespace, nothing else). Applications then show a deploy-status chip. See GitOps integration.
What good looks like
| Step | You should see |
|---|---|
| 1 · workspace | You land on Get set up in a new workspace |
| 3 · runner | kubectl -n "$NAMESPACE" get pods shows the runner pod 1/1 Running; the wizard shows Runner connected |
| 5 · repos | Both repos appear under Services (the platform repo with the Platform role) and on the Application’s detail page |
| 6 · profile | Stack lists the categories you declared |
| 7 · LLM | The provider shows as configured after the live check |
| 8 · analysis | Live events stream; the analysis reaches done with the right framework and runtime |
| 9 · proposal | Artifact validation passes, the policy gate shows allow, and a PR appears in your platform repo |
| 10 · CI | The caller workflow run in your service repo goes green and pushes an image |
| 11 · deploy | After you Sync, the ArgoCD Application is Healthy and Synced |
Troubleshooting
| Symptom | Likely cause and fix |
|---|---|
Runner pod stuck in Init | Check the init containers: kubectl -n "$NAMESPACE" describe pod -l app.kubernetes.io/name=runner. Usually an image pull blocked by egress; see network requirements. |
| Runner running but never shows connected | kubectl -n "$NAMESPACE" logs deploy/trustacks-runner-runner. Look for enrollment errors. Confirm the cluster can reach api.trustacks.com over HTTPS and that the token was pasted whole. Tokens do not expire, so a token from earlier is still valid unless someone revoked it on Runners; a revoked token can’t enroll a runner, so use its replacement. |
| Connect wizard says “Create an Application first” | Create one (step 4). |
| GitHub install returns to the app but shows no repos | The App was installed without access to those repos. Change the repo selection in GitHub under your account or organization’s installed GitHub Apps, then retry. |
| Analysis fails with an LLM error | Re-enter the key in Settings. Check the provider shows as configured, not pending. A pending key means your runner has not collected it yet; confirm the runner is connected. |
| Promote to proposal returns an error about clusters or the platform repo | The Application needs at least one target cluster and a bound platform repo. Check the Application detail page. |
| Proposal stops at policy, no PR | The policy gate denied it. The proposal page lists each rule and why. See the constitution. |
| Proposal stops at artifact validation | A generated file did not render or parse. The proposal page shows the failing check and its output. |
Caller workflow fails with workflow was not found | The platform repo is private and has not granted Actions access. Run the gh api command in step 10. |
| ArgoCD Application never appears | The root Application is not watching argo-apps/ with recursion, or ArgoCD cannot read the platform repo. |
| ArgoCD Application exists but nothing deployed | Emitted Applications use manual sync. Click Sync. |
Pod in ImagePullBackOff | Either the tag in values.yaml has no image yet (check the service repo’s CI run pushed one, then approve the tag-bump PR), or the GHCR package is private and the cluster has no pull secret for it. |
Beta limits
- Sign-in is email and password. Google and Microsoft sign-in are not enabled on the hosted service.
- Roles. Every workspace member is an owner.
- Git providers. GitHub is the supported provider for real repos.
- Monorepos connect as one service.
- Kustomize renderer support is Beta; Helm is the default.
- Customer overlay rules can be drafted in the Workspace chat and built with the CLI, but there is no way yet to deliver your own signed rules to a hosted runner.
- Billing. Self-serve billing may not be enabled for your workspace yet. Billing in the app says plainly whether it is configured. Pricing is at trustacks.com/pricing .
Remove everything
-
In Runners, click Remove on the runner.
-
Uninstall it:
helm uninstall trustacks-runner -n "$NAMESPACE"The runner writes two Secrets itself, so Helm does not remove them. Delete them if you are not reinstalling:
kubectl -n "$NAMESPACE" delete secret trustacks-runner-identity trustacks-runner-llm⚠️Removing a runner does not revoke its enrollment token. Tokens are reusable and do not expire. Delete every copy you hold (Helm values files, CI variables, the
trustacks-runner-enrollmentSecret if you created one). If a token may have leaked, revoke it on Runners with Revoke and generate a new token; see Revoke enrollment tokens. -
Uninstall the TruStacks GitHub App from your account or organization in GitHub if you no longer want it to have access.
Where to go next
- How TruStacks runs · what runs where, and what crosses the boundary
- Runner install · values, RBAC, egress, upgrades
- GitOps integration · the platform repo layout and the root Application
- Product guide · every screen in the app