Skip to Content
Getting startedQuickstart

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 amd64 and arm64.
  • kubectl pointed at that cluster, and helm 3.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 LLM key, which you paste in step 7. In the Beta program, TruStacks gives you an Anthropic key at no charge; it stops working when the Beta ends, so replace it with your own at least a day before then (a new key can take up to two hours to reach your runner). Outside the Beta, use your own Anthropic or OpenRouter key.
  • 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.

No Kubernetes cluster yet?

If you have Docker Desktop (or Docker Engine on Linux), you can run a small cluster on your own machine with k3d , which runs k3s inside containers. Running the cluster needs no root access, and k3d cluster delete trustacks removes it again.

  1. Start Docker Desktop (or Docker Engine on Linux). Using Podman instead? k3d needs extra setup for it first (the Podman socket and DOCKER_HOST, plus more for rootless Podman). Follow k3d with Podman , then continue at step 2.

  2. Install k3d, kubectl and helm.

    • macOS: brew install k3d kubectl helm
    • Linux: k3d’s own installer, curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash, then kubectl  and helm . The installer puts k3d in /usr/local/bin, so it may ask for your password (sudo).
    • Windows: follow the Windows instructions for k3d , kubectl  and helm , then use a PowerShell or WSL terminal.
  3. Create the cluster and check that its one node is Ready and its VERSION is v1.28 or newer:

    k3d cluster create trustacks kubectl get nodes

Already on Docker Desktop? You can turn on its built-in Kubernetes  instead of using k3d: in the Docker Desktop Dashboard, open the Kubernetes view, select Create cluster, keep the single-node Kubeadm option, and select Create. Then point kubectl at it, so the runner installs there and not in another cluster you use, and check that the node’s VERSION is v1.28 or newer (Docker Desktop picks the version; if it’s older, update Docker Desktop or use k3d):

kubectl config use-context docker-desktop kubectl get nodes

A cluster on your laptop is for trying TruStacks. The runner stops whenever the machine sleeps, so for day-to-day use, install it in a cluster that stays on. The same guide is in the app, on the runner step.

Step 1. Create your workspace

  1. Go to app.trustacks.com and click Create a workspace.
  2. Enter a Workspace name, your Work email and, if you’re in the Beta program, your Beta code. The code makes your first 45 days free, so there’s nothing to pay today.
  3. Click Continue to checkout (it reads Continue to payment when you leave the code blank). Stripe handles checkout; we never see your card.
  4. On the Stripe page, tick I agree to TruStacks’s Terms of Service and Privacy Policy and complete checkout.
  5. We email you a link to set your password. Don’t register again: your account already exists. Set the password from the email, return to app.trustacks.com, click Sign in, and you land on Get set up.

Your new workspace is isolated from every other, and you are its owner.

No Beta code? Checkout asks for a card and the subscription starts straight away. In the Beta program but don’t have your code? Ask in the support Discord  before you check out. No email after checkout? Check your spam folder; the page you return to can send it again.

Adding teammates. Invite colleagues from Team in the sidebar. They get an email and join your workspace. A teammate who signs up through Create a workspace starts a separate, separately billed workspace instead. During Beta every member is an owner. See the Team guide.

Step 1 · The Create a workspace form: workspace name, work email and an optional Beta code.

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 2 · Get set up, “Tell us about your team” with the optional company and team-size fields.

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.

  1. In the wizard (or Runners in the sidebar), click Generate enrollment token. The UI shows the token and a ready-made helm install command with the token already in it.

  2. 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 choose

    The 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.

  3. 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 enroll

    With the release name trustacks-runner, the deployment is named trustacks-runner-runner (the chart appends -runner).

  4. A few seconds after the runner enrolls, the wizard shows Runner connected. and ticks the step. Click Mark done & continue (or pick the next step) to go 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 3 · Generate enrollment token, with the copyable helm install command.

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.

  1. 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.
  2. 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, or prod). A new Application starts with one dev-tier cluster called dev. The name shows up in paths in your platform repo, and a cluster can’t be renamed: to use your own name, fill in cluster name and tier, click Add cluster, remove dev, then Save.
    • Renderer. Helm (the default) or Kustomize. Kustomize support is Beta. See the Applications guide.
Step 4 · Applications, “Create an Application” with a name typed and the Create button enabled.

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.

  1. Open Applications, click View all services across applications → (the services list, #/services), and click + Connect repo. (Step 3 of Get set up, Connect a repo, opens the same list.)
  2. Pick the role: Service (code to analyze) or Platform (where PRs land).
  3. 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.
  4. Back in TruStacks, pick the repo, the Application from step 4, and a name.
  5. 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 5 · + Connect repo opens the role picker: Service repo or Platform repo. GitHub then installs the TruStacks GitHub App and binds the repo to an Application.

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 container_registry: - provider: ghcr 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: true

Three things to know:

  • container_registry is required. It tells the DevOps Engineer where your image is published. Without it, Promote to proposal in step 9 stops at image_reference and no pull request opens. The wizard’s starter has it commented out, so uncomment it. For GitHub Container Registry, provider: ghcr is all it needs.
  • A category you leave out counts as a gap. It is not neutral, so your score understates what you run until you declare it.
  • practices are 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 6 · Get set up, “Declare what you run” with the 12 categories and the starter environment-profile.yaml.

Step 7. Set your LLM provider

Open Settings, choose Anthropic or OpenRouter, paste your key into API key and again into Confirm API key, and click Save + rotate. With OpenRouter, Model (required) must start with anthropic/.

  • The control plane checks the key’s shape and writes it to a single-use secret in TruStacks’ secret store that expires after two hours. Its database keeps only metadata (provider, the key’s first characters, status). Your runner collects the key sealed to its own key, writes the trustacks-runner-llm Secret in its namespace, and validates it with a live call to the provider. The stored copy is then deleted. If no runner collects it within two hours, save it again.
  • Nothing is rolled.
  • The banner says configured as soon as you save. It does not yet show whether your runner has collected and accepted the key. The first analysis in step 8 is the real check: if it fails with an LLM or config error, confirm the runner is connected on Runners and save the key again.
  • Agents run on Claude Sonnet 4.5 or newer. There is no model picker; you choose who bills you, not which model runs.

See LLM provider.

Step 7 · Settings, LLM provider with Anthropic selected and the key saved (key masked).

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 8 · A service’s analysis running: the Coordinator and Code Reviewer turns streaming in.

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:

  1. Artifact validation. The chart is rendered (helm template or kustomize build), the workflow is parsed, and names are checked. A check that could not run counts as a failure, not a pass.
  2. 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.
  3. 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 9 · Proposal detail: the Constitution’s “clean, no violations” turn and the “Pull request opened” banner.

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: write

Replace 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.

Grant what the workflow’s jobs need. The permissions above are a minimum for a workflow with no tool steps. A gitleaks step or a SARIF upload needs more, and GitHub refuses the run if the calling job grants less than a called job asks for. The pull request lists the set under Calling job permissions; grant at least that and keep what your calling job already grants. See The caller’s permissions.

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=user

The 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 10 · The platform-repo pull request on GitHub with the Preservation notes section, and the green CI run.
Save as public/screenshots/getting-started/10-pr-and-ci.png

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.

  1. 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).
  2. Apply one root Application that watches argo-apps/ in the platform repo. An example is in GitOps integration.
  3. 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.

Step 11 · Your ArgoCD showing the new Application Synced and Healthy.
Save as public/screenshots/getting-started/11-argocd-synced.png

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 /gaps in 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=argocd and 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

StepYou should see
1 · workspaceYou land on Get set up in a new workspace
3 · runnerkubectl -n "$NAMESPACE" get pods shows the runner pod 1/1 Running; the wizard shows Runner connected
5 · reposBoth repos appear on the services list (the platform repo with the Platform role) and on the Application’s detail page
6 · profileStack lists the categories you declared
7 · LLMThe banner shows your provider as configured; the first analysis in step 8 confirms the runner accepted the key
8 · analysisLive events stream; the analysis reaches done with the right framework and runtime
9 · proposalArtifact validation passes, the policy gate shows allow, and a PR appears in your platform repo
10 · CIThe caller workflow run in your service repo goes green and pushes an image
11 · deployAfter you Sync, the ArgoCD Application is Healthy and Synced

Troubleshooting

SymptomLikely cause and fix
Runner pod stuck in InitCheck 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 connectedkubectl -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).
You are back on sign-in with “Your session expired. Sign in again to continue.”Your session could not be renewed. Sign in again. Earlier releases showed an empty workspace instead; nothing was lost.
GitHub install returns to the app but shows no reposThe 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 errorIf the provider rejected the key, check the key itself, your provider account’s credit, and (on OpenRouter) that the model starts with anthropic/, then save the key again in Settings (Save + rotate). If the runner never collected it, confirm the runner is connected on Runners and save it again: a saved key waits up to two hours for a runner to collect it.
Promote to proposal stops at image_referenceYour Environment Profile declares no container_registry. Add one (step 6) and promote again.
Promote to proposal returns an error about clusters or the platform repoThe Application needs at least one target cluster and a bound platform repo. Check the Application detail page.
Proposal stops at policy, no PRThe policy gate denied it. The proposal page lists each rule and why. See the constitution.
Proposal stops at artifact validationA generated file did not render or parse. The proposal page shows the failing check and its output.
Caller workflow fails with workflow was not foundThe platform repo is private and has not granted Actions access. Run the gh api command in step 10.
ArgoCD Application never appearsThe root Application is not watching argo-apps/ with recursion, or ArgoCD cannot read the platform repo.
ArgoCD Application exists but nothing deployedEmitted Applications use manual sync. Click Sync.
Pod in ImagePullBackOffEither 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 need runner 0.2.17 or later, which loads them from rules/ in your platform repo. Proposing a drafted rule as a pull request from the chat needs runner 0.2.18. See Add your own rule.
  • Billing. A Beta code makes the first 45 days free. The strip at the top of the app shows Free until a date with the days left; add a card under Billing → Manage billing before then to keep going. See Billing. Pricing is at trustacks.com/pricing .

Remove everything

  1. In Runners, click Remove on the runner.

  2. 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-enrollment Secret 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.

  3. 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

Last updated on