Skip to content

Team Brain

The Team Brain is one shared service per team. Every contributor’s workspace pushes tier-tagged content to it via the aios CLI; the brain turns that stream into a live dashboard of what the team is doing and deciding, and answers natural-language questions over the whole corpus with cited sources.

You run one instance per team. It’s a Next.js + Postgres app you can self-host anywhere.


The brain opens on Pulse — the team’s home surface. It leads with the brain’s synthesized understanding (the story of the team right now), not raw analytics.

Pulse answers “what is my team’s brain telling me right now?” in about ten seconds:

  • Narrative arcs (the hero) — the brain reads across everyone’s synced work and writes the current storylines: what’s moving, who’s driving it, what it connects to.
  • Working on — per person, their most recent day of work, with the evidence (tasks, decisions, deliverables) nested underneath.
  • Timeline — the same work broken down day by day (collapsed by default).
  • Metrics — knowledge growth, brain usage, and the task funnel (open for admins).
  • Evidence trail — the raw events and atomic facts the arcs are built from.

A slim ask bar sits at the top of Pulse and hands any question straight to Chat.

Chat is a grounded question-and-answer over the team’s shared memory — Slack, decisions, tasks, code, meeting transcripts, and the knowledge graph. Every answer cites its sources, so you can trace a claim back to the item it came from.

Ask things like “what decisions were made about auth last sprint?” or “who owns onboarding, and what’s blocked?” — the answer streams in with the decisions, tasks, and documents it drew on linked inline.

Meetings collects synced call transcripts and pulls out the action items and decisions from each one, so the follow-ups from a call become tracked work in the brain rather than dying in someone’s notes.

Codebases shows the health, test coverage, and AI-transformation progress across the team’s repos, plus on-demand GitHub scans — the engineering surface of the same brain.

A repo only fills that dashboard once you wire it in. Linking a repo without the scan workflow leaves its readiness, health, and coverage permanently null.

Everyone has an Account page to manage their own API keys. Admins additionally get an Admin area to invite members, issue and revoke keys, wire integrations, and pick the team’s active answering model (see Pluggable LLM).


Contributors never write to the brain by hand. Each workspace runs aios push, which sends its content to the narrow, audited ingest path:

Contributor workspaces (N×)
│
│ aios push (POST /api/v1/items)
▼
┌──────────────┐
│ Team Brain │ Next.js 16 + Postgres
│ ingest lib │ narrow, audited write path
│ query lib │ FTS + structured context + LLM streaming
│ dashboard │ Pulse · Chat · Meetings · Codebases
└──────────────┘

Every item carries an access tier, and the brain enforces tier filtering on every read — in app code, since there is no row-level security backstop.

TierWho can see it
teamAll authenticated team members
externalAll team members — it’s the outward-facing surface for clients/collaborators
adminRejected at the ingest API with 422 — never stored

Auth model:

  • People sign in with email + password — invite-only (an admin creates the member row first, and that step is what mints the password). There is no OAuth sign-in: no Google, GitHub, or SSO provider button exists.
  • Magic-link email is an optional second method, not the default. It appears on the sign-in form only when the deployment has both APP_URL and a mail provider (RESEND_API_KEY or SMTP_URL) set as environment variables. Without them the brain accepts the request, returns 200, and silently delivers nothing — so treat the password as the real credential unless you have deliberately configured mail.
  • Machines authenticate with per-member API keys (aios_<key_id>_<secret>, SHA-256 at rest, shown once at creation).

The brain is organized internally as eight organ systems — knowledge, ingestion, context, actions, identity, policy, audit, and feedback. See The 8 organ systems for the anatomy reference with shipped / partial / planned status.


Content reaches the brain through aios push. Code does not. A repo reports itself by running a scan-on-merge GitHub Actions workflow, which scans the checkout after every merge and POSTs the result to /api/v1/codebases.

Without that workflow the brain still knows the repo exists — it falls back to the GitHub API for identity and contribution rows — but it has no checkout, so it deliberately writes no code metrics. A linked-but-unscanned repo shows null readiness, null health, and null coverage forever, and nothing anywhere reports an error.

RepoWhat to do
A scaffolded workspaceNothing — the scaffold ships .github/workflows/scan-on-merge.yml already.
Any other repo you want on the dashboard (product, service, docs)Copy the workflow in by hand.

The four files live in the toolkit scaffold at scaffold/.github/; copy all of them, preserving paths:

.github/workflows/scan-on-merge.yml
.github/scripts/fetch-brain-scanner.sh
.github/scripts/scan_with_health.py
.github/scripts/brain-scanner-requirements.txt

The workflow is repo-agnostic — it derives the codebase slug from GITHUB_REPOSITORY and assumes nothing about the six-folder workspace spine, so it drops into an app or library repo unchanged. It triggers on push to main; rename the branch in the on: block if your default branch is something else.

Every repo needs its own three GitHub Actions secrets. Actions secrets do not inherit across repositories — setting them once on one repo does nothing for the next. (An organization-level secret shared to the relevant repos is the sane answer once you have more than a handful.)

SecretValue
AIOS_BRAIN_URLYour brain’s base URL, e.g. https://your-brain.up.railway.app
AIOS_TEAMYour team slug
AIOS_API_KEYAn API key belonging to a team-tier member (aios_<key_id>_<secret>)
Terminal window
gh secret set AIOS_BRAIN_URL --body "https://your-brain.example.com" -R your-org/your-repo
gh secret set AIOS_TEAM --body "your-team" -R your-org/your-repo
gh secret set AIOS_API_KEY --body "aios_..." -R your-org/your-repo

This workflow is fail-open by design: if any of the three secrets is missing or blank it prints a skip note and exits 0. That is intentional — a repo with no brain credentials stays green rather than going red — but it means a green check is not evidence a scan happened. This is the single most common way a repo silently stays off the dashboard.

A real scan takes roughly 60–90 seconds. A skipped one finishes in about 10.

Terminal window
gh run list -R your-org/your-repo --workflow scan-on-merge.yml --limit 1
gh run view <run-id> -R your-org/your-repo --log \
| grep -E 'codebase_id|skipping the scan'
What you seeWhat it means
{"status": "ok", "codebase_id": "..."}The scan reached the brain. This is the proof.
Brain credentials not configured — skipping the scan.One or more secrets are unset or empty. Nothing was sent.
403 forbidden_tierThe secrets resolved, but AIOS_API_KEY is not a team-tier key.

Then confirm the row appears under Codebases in the dashboard with non-null readiness and health.


The brain is self-host portable — plain SQL migrations, Postgres-backed rate limiting, no host-only dependencies. Any Postgres works; deploy anywhere that runs Next.js.

The fastest path is the Railway deploy template — the maintained one-click install, reached by direct link rather than by searching Railway’s public template gallery, which does not list it. It creates the Team Brain app and a managed Postgres service together, generates the application secrets, and asks only for your team and first-admin details. Railway shows the resources and estimated charges before you deploy. No GitHub fork or local Railway CLI is required. An active Railway plan in the workspace that will own the deployment is a prerequisite; an expired trial cannot create the project.

The first-admin password must be at least 10 characters. Railway’s form accepts a shorter one, and the deployment then fails while bootstrapping the admin, after Postgres has already been provisioned.

After the deployment is healthy, sign in with the admin credentials you supplied, create an API key under Account, then return to aios onboard and connect the workspace with the deployed Brain URL and that key.

For a local or non-Railway install, use the manual steps below.

  1. Clone and install

    Terminal window
    git clone https://github.com/aiosbrain/aios-team-brain
    cd aios-team-brain
    npm install
  2. Start a Postgres database

    Any Postgres works. For a local throwaway DB, use the repo’s ephemeral test Postgres:

    Terminal window
    npm run db:test:up # ephemeral Postgres on port 5434
  3. Configure environment

    Terminal window
    cp .env.example .env.local
    Terminal window
    DATABASE_URL=postgres://app:app@localhost:5434/app_test
    PGSSL=require # only for a managed Postgres with TLS
    AUTH_SECRET=<random string — signs the session cookie>
    SECRETS_KEY=<32 bytes, hex or base64 — encrypts stored connector secrets>
    APP_URL=http://localhost:3000
    ANTHROPIC_API_KEY=<your key>
    # optional — magic-link login only. Password sign-in works without these.
    # RESEND_API_KEY=<your key>
    # RESEND_FROM="Team Brain <brain@example.com>"
    # …or SMTP
    # SMTP_URL=smtp://user:pass@host:587
    # SMTP_FROM="Team Brain <brain@example.com>"

    The DATABASE_URL above matches the credentials the step-2 test database is created with (app / app / app_test on port 5434). Pointing at postgres:postgres there fails to authenticate and npm run pg:schema dies in the next step.

    Generate SECRETS_KEY with openssl rand -hex 32. The app boots without it — you get a [boot] warning, not a crash — but every Admin → Integrations connector save then fails with SECRETS_KEY is required to store/read connector secrets, and any feature that reads a stored connector secret returns a 500. Set it before you start wiring integrations, and never rotate it without re-entering every secret: it is the AES-256-GCM key those ciphertexts were written with.

  4. Load the schema

    Terminal window
    npm run pg:schema # loads postgres/schema.sql into DATABASE_URL
  5. Create your team and your admin login

    Do not skip this. The schema creates tables, not accounts — without this step you reach the sign-in page with no credential to sign in with.

    The admin CLI reads DATABASE_URL from the environment rather than .env.local, so export it first:

    Terminal window
    export DATABASE_URL=postgres://app:app@localhost:5434/app_test
    npm run admin -- create-team acme --name "Acme Robotics"
    npm run admin -- create-member you@acme.com \
    --name "Your Name" --handle you --role admin --team acme

    create-member generates a password and prints it once:

    ✓ password set (copy now, shown once): <password>

    Copy it — that is how you log in. Pass --password <your-own> to choose your own instead; either way it must be at least 10 characters.

  6. Seed demo data (optional)

    Terminal window
    npx tsx --conditions react-server scripts/seed-demo.ts

    This populates a separate demo team so the dashboard has something to show. The seed prints a demo API key once — save it if you want it. It is not a sign-in credential: seeded members are created without passwords and cannot log in. Your real login is the one from step 5.

  7. Run the dev server

    Terminal window
    npm run dev
    # → http://localhost:3000

    Sign in at /login with the email and password from step 5, then create your own API key under Account and point a workspace at http://localhost:3000.

For Railway, use the maintained Team Brain template; it provisions the app, Postgres, schema bootstrap, public URL, and required secrets as one reviewed bundle. For another host, provision a managed Postgres, point DATABASE_URL at it (PGSSL=require), and run npm run pg:schema to load the schema. Add the required env vars (AUTH_SECRET, APP_URL, email, ANTHROPIC_API_KEY) to your host, then deploy the aios-team-brain repo. Point each workspace’s aios.yaml at the production URL.

Answering is provider-agnostic. Admins choose the team’s active answering model from the Admin area — Anthropic, OpenRouter, or any OpenAI-compatible backend — and it applies to the whole team’s chat and synthesis (arcs, meeting extraction, and so on) through one switch. No rebuild required.

To run fully on-machine (no API cost), point the default at a local endpoint:

.env.local
LLM_BASE_URL=http://localhost:11434/v1 # Ollama endpoint
LLM_MODEL=llama3.1 # any local model

Embeddings and the reranker are a separate model class with their own configuration. See docs/PROVIDERS.md.


Chat is also available over the CLI — the same tier-filtered, cited pipeline the dashboard uses:

Terminal window
aios query "what decisions were made about auth in sprint 1?"
# → SSE stream: delta chunks, source citations, done signal

The pipeline: FTS retrieval over tier-filtered content → structured context injection (decisions, tasks, knowledge-graph entities) → LLM streaming, with per-member and per-team daily cost guards.