Status: working research project from Borge Labs, published as-is. It runs our own Slack workspace every day, but it is not a supported product: issues and PRs are welcome but may go unanswered.
AI Team is an open-source, Slack-native AI staff framework for small, high-context teams. It gives a Slack workspace configurable AI teammates who can follow discussions, remember decisions, understand docs and repositories, inspect public web pages and, in the opt-in browser build, screenshots, and help move work forward without adding another app.
Instead of one generic chatbot, AI Team behaves like a coordinated team. Each teammate has a name, role, model, tools and scope. A team lead routes questions to the right specialists, or coordinates a combined answer when a topic needs product, technical, design, growth, research, legal-style compliance or operational input.
Teammates discuss, draft, review and recommend. Irreversible actions should stay human-approved and tool-gated.
- Slack-first: the team works where company discussions already happen.
- Team-shaped: configure named teammates with roles, models, prompts and tools.
- Context-aware: combine thread history, channel memory, live docs, repo context, web reads, screenshots and uploaded images.
- Workstream-scoped: each channel can have its own context boundary, repository scope and operating rules.
- Model-agnostic: route different teammates to different providers based on quality, cost and latency.
- Open-source and config-first: keep the framework generic, then mount your own config, secrets and deployment choices.
AI Team can help teams:
- discuss strategy, product, technical, design, growth, legal-style and operational questions with role-matched teammates
- answer from real context: configured GitHub repositories, team docs, thread history and per-channel memory
- read public web pages, search the web, and capture pages or screenshots for UI/UX review; analyze uploaded images and mockups
- draft and consolidate prompts for coding agents
- run daily kickoff threads, scheduled checks and public-URL watchers, all confirmed from Slack
- preserve durable decisions per workstream while keeping channel context separate
- update exactly allowlisted Markdown docs through a GitHub App on an explicit request from a configured Slack admin
- log estimated model usage and stop new runtime calls at a configurable soft daily threshold
Automations are notify-only by default. They can monitor, summarize, draft and recommend in Slack; irreversible external actions still need explicit human approval and a safe tool path.
Ask:
What changed in the repo since yesterday?
The technical teammate can check configured GitHub repositories, compare current state with indexed context, and explain the impact in Slack.
Ask:
Review this landing page against our positioning.
Product, growth and design teammates can inspect a public URL or screenshot, compare it with saved direction, and return a practical recommendation.
Ask:
Summarize what we decided in this thread and remember it.
The team can turn a Slack discussion into durable memory or an updated Markdown doc, scoped to the right workstream.
Ask:
Can the legal/compliance teammate review this privacy copy?
A configured compliance-oriented teammate can issue-spot, draft safer wording and flag legal risk. It is support for human review, not legal advice.
AI Team combines several context layers:
- recent channel context for short-term awareness
- full thread context for ongoing discussions
- live team docs stored in Postgres
- saved decision-grade memories
- indexed repository chunks from GitHub
- live GitHub, web, URL, screenshot and image context when relevant
Memory is scoped by channel and workstream to reduce context bleed between projects. Slack deletion events can remove matching source messages and derived memory/artifacts.
context-pack.md is only bootstrap context. After startup, live memory and team
docs live in Postgres.
Admins configure:
- allowed Slack channels
- teammates, roles, models, tools and routing hints
- repository scopes per channel
- memory document keys and bootstrap context
- exact, admin-only GitHub Markdown update targets
- provider credentials through environment variables or secret managers
- best-effort estimated runtime-model thresholds and usage logging
The framework blocks unsafe public URL targets such as localhost, private network addresses and metadata hosts. Secrets should never live in config files.
Before connecting a real workspace, read Privacy and Threat Model. This service stores Slack content and can send selected working context to model providers; it has no automatic retention period.
You need Docker with Compose, a Slack workspace where you can install an app, an OpenAI API key, and a public HTTPS URL that Slack can reach. The first run builds the image locally; it does not depend on GHCR being public.
In Slack, first create a blank app from scratch for your workspace. Copy its signing secret from Basic Information, but do not enable Socket Mode.
Create the documented three-person, one-provider starter config and environment file:
cp -R starter-config my-config
cp .env.example .envSet OPENAI_API_KEY and the blank app's SLACK_SIGNING_SECRET in .env, then
replace the placeholder company context in my-config/context-pack.md. Leave
the bot token empty for this bootstrap start and run:
docker compose up --build -d
docker compose ps
curl --fail http://localhost:8080/healthzCompose starts Postgres with pgvector, waits for it to become healthy, applies all numbered migrations exactly once, starts AI Team, and persists database and artifact data in named volumes.
A one-shot artifact-init service gives UID/GID 10001 ownership of the artifact
volume before AI Team starts. The initializer exits after that narrow operation;
the application itself continues to run as the non-root UID/GID 10001.
Port 8080 binds to 127.0.0.1 by default. Configure your public HTTPS ingress
or development tunnel to proxy to that loopback address; do not publish the
plain HTTP app port directly on an external interface.
Now replace both https://ai-team.example.com URLs in
slack-app-manifest.yaml with your public HTTPS origin.
Open App Manifest for the existing blank Slack app and apply that YAML. Slack
can now verify the signed callback against the running service. Install the app,
then copy its bot token and an allowed channel ID into .env. Restart with
docker compose up -d and invite the bot. See Slack App for the
exact callback flow.
Setting DATABASE_URL alone does not disable the bundled database service. For
operator-managed Postgres+pgvector, set the full URL and use the override (Docker
Compose 2.24.4 or newer):
docker compose -f docker-compose.yml -f docker-compose.external-db.yml up --build -dThe override removes Postgres from AI Team's dependencies and leaves the bundled
service behind a disabled profile. Set AI_TEAM_RUN_MIGRATIONS=false only when
your deployment process has already applied every numbered migration. That flag
skips both entrypoint migrations and runtime compatibility DDL; the app still
expects the complete schema and performs normal reads/writes.
The bundled URL interpolates POSTGRES_PASSWORD directly. Keep that local
password URL-safe (letters, digits, ., _, ~, or -). For a password with
reserved URL characters, keep the raw value in POSTGRES_PASSWORD and set an
explicit DATABASE_URL whose password component is percent-encoded.
The richer example-config/ demonstrates more roles, workstreams and optional integrations after the starter is working.
The repository is intentionally buildable before its container package is public. A research release should publish a versioned image tag such as:
ghcr.io/borge-labs/ai-team:0.1.0-research
The version tag is a human-readable release pointer; only the resolved image
digest is immutable. Operators can then use the published image from their
container platform. The published/default runtime target uses a pinned Alpine
base and deliberately omits Playwright and Chromium. Do not rely on latest for
a known-good deployment. Making the GHCR package public is a separate release
action; this repository does not change package or repository visibility.
Browser capture is disabled by default and is not present in the published
Alpine runtime image. The opt-in browser target uses pinned Debian/Trixie for
Playwright's glibc-based Chromium. To test it locally, set both of these values
in .env and rebuild:
AI_TEAM_BUILD_TARGET=browser
AI_TEAM_WEB_CAPTURE_ENABLED=truedocker compose up --build -dFor a Python installation, install the optional dependency with
python -m pip install -e '.[browser]', then run
python -m playwright install --with-deps chromium as an operator-controlled
setup step. Chromium runs with --no-sandbox; use the browser target only in a
separate disposable environment with no secrets or private-network access. The
normal application container is not a security boundary for hostile pages.
Compose mounts your config read-only:
./my-config -> /app/config
CONFIG_PATH must point to a directory containing:
team.yaml: team name, language, roster, aliases, model choices, routing policy, tool hints and bootstrap document keys.context-pack.md: one-time seed context for live team docs.personas/*.md: long-form persona instructions.
Use starter-config/ for the first deployment and example-config/ to explore the fuller contract. See CONFIG.md for details.
| Name | Required | Description |
|---|---|---|
SLACK_BOT_TOKEN |
Yes | Slack bot token used to post messages. |
SLACK_SIGNING_SECRET |
Yes | Verifies every Slack HTTPS event and interaction request. |
OPENAI_API_KEY |
For the starter | The starter config's only model-provider credential. |
AI_TEAM_UTILITY_MODEL |
Optional | Model for background summaries, open-loop tracking, memory updates, GitHub Markdown drafting and opt-in casting feedback. Defaults to AI_TEAM_CHAIR_ROUTER_MODEL; the starter pins both to OpenAI. |
AI_TEAM_FALLBACK_MODELS |
Optional | Ordered comma-separated fallback models for failed/refused chat calls. Empty by default. Each entry is an explicit choice to resend the same Slack/context payload to that model/provider. |
CONFIG_PATH |
No | Config directory inside the container. Compose sets /app/config. |
SLACK_BOARDROOM_CHANNEL_ID |
For the starter | Primary Slack channel and the starter's default allow-list. |
SLACK_ALLOWED_CHANNEL_IDS |
Optional | Additional comma-separated channels the app may answer in. If no channel IDs are configured anywhere, Slack events fail closed. |
SLACK_PROJECT_CONTEXT_CHANNEL_ID |
Optional | Channel that owns shared live team docs. Defaults to the primary channel. |
AI_TEAM_ADMIN_SLACK_USER_IDS |
For action approvals | Comma-separated Slack user IDs allowed to approve/deny/abort coding jobs, apply allowlisted GitHub Markdown writes, and administer another user's automation. |
DATABASE_URL |
In production | Postgres+pgvector connection string. Compose supplies a local default when empty. |
AI_TEAM_RUN_MIGRATIONS |
Optional | Apply numbered migrations and allow runtime compatibility DDL. Defaults to true; set false only for a complete externally managed schema. |
AI_TEAM_INTERNAL_TOKEN |
Optional | Bearer token for protected maintenance endpoints. |
ANTHROPIC_API_KEY |
Optional | Enables anthropic/... models. |
DEEPSEEK_API_KEY |
Optional | Enables deepseek/... models. |
MIMO_API_KEY |
Optional | Enables mimo/... models. |
OPENROUTER_API_KEY |
Optional | Enables openrouter/... models through the OpenRouter gateway, for example openrouter/z-ai/glm-5.2. |
GOOGLE_CLOUD_PROJECT / VERTEX_PROJECT |
For Vertex/Gemini features | Enables Vertex models, embeddings, web search and image generation. |
AI_TEAM_GCS_BUCKET |
For persisted visual artifacts | Stores screenshots and generated images. |
AI_TEAM_ARTIFACT_DIR |
Optional | Local/PVC artifact directory for screenshots and generated images when GCS is not used. |
AI_TEAM_ARTIFACT_BASE_URL |
Optional | Public or internal URL prefix for locally stored artifacts. |
AI_TEAM_LOCAL_AI_BASE_URL |
Optional | OpenAI-compatible /v1 base URL for local chat or vision models, for example llama.cpp/vLLM. |
AI_TEAM_LOCAL_AI_API_KEY |
Optional | Bearer token for the local OpenAI-compatible model endpoint, if required. |
AI_TEAM_PERSONAL_DATA_EGRESS |
Optional | Text-payload policy for real Norwegian personal identifiers (fødselsnummer/D-nummer) sent to OpenAI/Anthropic/DeepSeek/MiMo/OpenRouter: redact (default), block, or off. It cannot inspect image bytes or custom embedding/web-gateway calls. Vertex and local/ models bypass it; verify their actual region/endpoints separately. |
AI_TEAM_VISION_MODEL |
Optional | Primary model used for screenshot and uploaded-image analysis. Supports Vertex, OpenAI-compatible MiMo/OpenRouter, and local/<served-model> with AI_TEAM_LOCAL_AI_BASE_URL. Defaults to VERTEX_VISION_MODEL (google/gemini-3.1-pro-preview). Long pages are captured as viewport-height tiles so text stays legible. |
AI_TEAM_VISION_FALLBACK_MODEL |
Optional | Secondary vision model tried when the primary vision model fails. Defaults to google/gemini-3.5-flash. |
AI_TEAM_EMBEDDING_BASE_URL |
Optional | OpenAI-compatible /v1 base URL for repo-context embeddings. |
AI_TEAM_EMBEDDING_API_KEY |
Optional | Bearer token for the OpenAI-compatible embedding backend. |
AI_TEAM_EMBEDDING_MODEL |
Optional | Embedding model name for repository/context semantic search. Empty disables embedding calls; setting it explicitly uses the configured embedding backend or Vertex project. |
AI_TEAM_EMBEDDING_VECTOR_DIMENSIONS |
Optional | Truncate embedding vectors to match the database schema, for example 768. |
AI_TEAM_WEB_RESEARCH_GATEWAY_URL |
Optional | Screened web gateway URL for public web/source context instead of Vertex Google Search grounding. |
AI_TEAM_IMAGE_GENERATION_ENABLED |
Optional | Enables the image generation button/action. Defaults to false. |
AI_TEAM_IMAGE_MODEL |
Optional | Image generation model when image generation is enabled. Defaults to VERTEX_IMAGE_MODEL. |
AI_TEAM_IMAGE_ESTIMATED_COST_USD |
Optional | Fixed estimated cost recorded after each successful image-generation provider call. Defaults to 0.05; image APIs do not report token usage here. |
GITHUB_APP_ID |
Optional | GitHub App id for repo indexing and Markdown updates. |
GITHUB_APP_PRIVATE_KEY_PEM |
Optional | GitHub App private key, supplied only through environment/secrets. |
GITHUB_APP_INSTALLATION_ID |
Optional | GitHub App installation id. |
GITHUB_ADDITIONAL_APPS |
Optional | Additional owner=app_id:installation_id:PRIVATE_KEY_ENV app mappings. |
GITHUB_REPOS |
Optional | Comma-separated owner/repo or owner/* repo specs to index. |
GITHUB_REPO_CHANNEL_SCOPES |
Optional | Per-channel repo read/index scopes in `C1=owner/repo |
GITHUB_MARKDOWN_UPDATE_TARGETS |
Optional | Exact admin-only write allowlist in alias=owner/repo:path.md form. Repository scopes grant reads only; an empty target list disables Markdown writes. |
AI_DEV_TEAM_BASE_URL |
Optional | Internal base URL for a separate AI Dev Team addon service. |
AI_DEV_TEAM_INTERNAL_TOKEN |
Optional | Bearer token AI Team uses when calling the AI Dev Team addon. |
AI_DEV_TEAM_WEB_URL |
Optional | Public web UI URL included in Slack status messages. |
AI_DEV_TEAM_REPO_CHANNEL_SCOPES |
Required for persona create/promote | Separate action allowlist in `C1=owner/repo |
AI_TEAM_TIMEZONE |
Optional | Workspace timezone used for local-day estimated-usage boundaries and kickoffs. Defaults to UTC; DST days use their real 23/25-hour UTC interval. |
AI_TEAM_DAILY_BUDGET_USD |
Optional | Soft estimated runtime-model threshold. Defaults to 3; this is not a provider billing cap. |
AI_TEAM_MAX_PERSONAS_PER_EVENT |
Optional | Max teammates selected per event. Defaults to 5. |
AI_TEAM_WEB_SEARCH_ENABLED |
Optional | Enable public web/source reading. Defaults to false. A persona must also have the relevant tool. |
AI_TEAM_EXPERT_CONSULT_ENABLED |
Optional | Expose configured expert-consult model calls to eligible personas. Defaults to false. |
AI_TEAM_BUILD_TARGET |
Compose only | Docker build target: runtime (default, no Playwright/Chromium) or opt-in browser. |
AI_TEAM_WEB_CAPTURE_ENABLED |
Optional | Expose and enable browser screenshot capture. Defaults to false; also requires the browser image target or Python browser extra. |
AI_TEAM_MAX_IMAGE_BYTES |
Optional | Maximum Slack image upload size accepted for vision analysis. Defaults to 10000000. |
AI_TEAM_AUTOMATIONS_ENABLED |
Optional | Enable confirmed scheduled checks/watchers. Defaults to false. |
AI_TEAM_AUTOMATION_TIMEZONE |
Optional | Default timezone for human schedule parsing. Defaults to UTC. |
AI_TEAM_MEMORY_CURATOR_ENABLED |
Optional | Let model-based curation inspect ordinary human messages/thread excerpts and persist selected decision-grade channel memory or project docs. Defaults to false; explicit remember/update commands remain available when it is off. |
AI_TEAM_CASTING_FEEDBACK_ENABLED |
Optional | Send multi-person Slack rounds to AI_TEAM_UTILITY_MODEL for contribution scoring. Defaults to false. |
Browser capture defaults off in both settings and the supplied .env.example;
disabled means its persona tool is neither exposed nor executed. The starter
also pins its router and utility model to OpenAI, leaves the explicit fallback
list empty, and disables casting feedback, web search, automations, expert consultation and
automatic memory curation. Review
and configure each optional feature's provider, storage, network and approval
requirements before enabling it.
AI_TEAM_DAILY_BUDGET_USD is a best-effort preflight threshold over usage that
AI Team has estimated and recorded for the current AI_TEAM_TIMEZONE calendar
day. When the recorded estimate is already at or above the threshold, the app
does not start a new normal Slack turn, automation model run, daily-kickoff
model round, AI Dev Team terminal-report draft or image-generation request.
It is deliberately not described as a hard spend cap. A call that starts below
the threshold can finish above it, and concurrent/in-flight turns can overshoot.
Provider billing can drift from the local pricing table; unknown or unpriced
models can record $0; and some tool, retry or continuation accounting can be
incomplete. Embedding calls are outside this guardrail, including repository
embeddings started through the protected operator-only /internal/ingest-repos
endpoint. Configure provider-side billing alerts/quotas separately.
Successful image generation records zero tokens plus the fixed
AI_TEAM_IMAGE_ESTIMATED_COST_USD estimate and explicit estimate metadata.
Never commit real secrets. Use .env locally and a secret manager in
production.
AI Team implements Slack's HTTPS Events API and interactive-component callback. It does not implement Socket Mode and does not use a Slack app-level token.
- Create a blank Slack app from scratch, copy its signing secret into
.env, then start AI Team and its public HTTPS proxy/tunnel. This avoids the circular dependency between obtaining a signing secret and Slack verifying a signed Events API challenge. - Copy slack-app-manifest.yaml, replace both example origins, open App Manifest on that existing app, and apply the YAML.
- Review the scopes and install it to the workspace. Put the resulting bot
token and allowed channel ID in
.env, then restart AI Team. Never put bot tokens or the signing secret in the manifest. - In Event Subscriptions, confirm Slack verifies
https://<service>/slack/events. In Interactivity & Shortcuts, confirmhttps://<service>/slack/interactions. - Invite the bot to the boardroom and each channel listed in
SLACK_ALLOWED_CHANNEL_IDS.
The included manifest subscribes only to message.channels and
message.groups. Message deletion arrives as a message subtype; there is no
separate message.deleted subscription. The baseline deliberately omits
file_shared: the runtime does not dispatch that event, and retaining it would
collect file metadata without providing a working feature.
The baseline callback settings are:
- Event Request URL:
https://<service>/slack/events - Interaction URL:
https://<service>/slack/interactions - Bot scopes:
chat:write,chat:write.customize,channels:history,groups:history. - Add
channels:read,channels:manageandchannels:joinif you want the app to create, rename or manage configured public channels. - Invite the app bot to each allowed channel.
File handling is opt-in. Add files:read only when you intend to analyze image
attachments included in allowed-channel message events. Add files:write only
when AI Team should upload browser screenshots or generated artifacts back to
Slack. Reinstall the Slack app after changing scopes. Do not add a standalone
file_shared subscription; attachment handling is driven by the allowed
message.* event and must remain within the channel allow-list.
The app posts as separate teammates by setting display names and icons per
message through Slack's chat:write.customize scope.
Slack must reach both endpoints over HTTPS with a valid public certificate. Put
the app behind a reverse proxy or managed ingress that preserves the request
body and Slack signature headers. Do not expose internal maintenance endpoints
without a strong AI_TEAM_INTERNAL_TOKEN and network-level access controls.
AI Team can bridge Slack requests into a separate AI Dev Team coding runtime. The coding runtime does not need its own Slack app: this service receives Slack events and interactions, renders approval/status messages, and calls the addon through its internal HTTP API.
Set AI_DEV_TEAM_BASE_URL and AI_DEV_TEAM_INTERNAL_TOKEN to enable requests
such as "get our dev team to work on repo owner/name ...", status checks, and
approval/deny/abort buttons in Slack.
Before allowing a persona to create or promote jobs, set a separate exact
action scope, for example
AI_DEV_TEAM_REPO_CHANNEL_SCOPES=C1=owner/repo|owner/other;C2=org/repo.
This scope never inherits GITHUB_REPOS, channel profiles or
GITHUB_REPO_CHANNEL_SCOPES: those are read/index permissions, not coding-agent
action authority. Wildcards are rejected. An empty action scope leaves status
for channel-provenance jobs available but disables persona creation and Slack
promotion.
Set AI_TEAM_ADMIN_SLACK_USER_IDS before enabling the addon. Creating jobs is
approval-gated, and only those Slack users can approve, deny or abort jobs.
Approve and deny buttons bind both the job UUID and the immutable approval UUID
returned by AI Dev Team; abort remains bound only to the job UUID. Legacy,
malformed, cross-action, or stale button values fail closed and ask the admin to
refresh status. A direct text command containing only a job UUID performs one
status read, accepts only a pending_approval job with a non-action
pendingApproval, and submits that exact approval UUID once. It never retries a
409 against a newer approval.
Status and list paths verify the authoritative ai_team.job or
session.promoted origin event from each detailed job response before showing
it in a Slack channel. Global list records are never displayed without that
bounded detail check. Free-text approve, deny and abort commands also verify
channel provenance before mutation. Structured buttons remain bound to the
verified Slack message that rendered them; approve/deny use the embedded exact
approval UUID without a reload or retry.
Only personas with ai_dev_team in their tools: list can call the addon as a
private tool. Treat it as an action tool, not a read-only context tool: the
example config limits it to technical implementation owners. Personas cannot
message/steer, approve, deny or abort coding jobs and cannot disable the
approval gate. The configured Slack admins and the AI Dev Team service remain
trusted; these application checks are not a hard multi-tenant boundary.
Install a GitHub App on repositories listed in GITHUB_REPOS.
Repository permissions:
- Metadata: read-only.
- Contents: read-only for repository context.
- Contents: read and write only when exact Markdown targets are deliberately enabled.
GITHUB_REPOS and per-channel scopes grant reads only. Writes require an exact
GITHUB_MARKDOWN_UPDATE_TARGETS entry, an explicit Slack request and a user in
AI_TEAM_ADMIN_SLACK_USER_IDS; an empty target list disables writes. To prevent
ordinary discussion from becoming a write, the affirmative request must end
with the literal line CONFIRM GITHUB WRITE. GitHub rejects the update if the
target changed while the model prepared its draft.
The app uses Postgres with pgvector for durable memory, Slack history, repo
chunks, artifact metadata and usage logs. The container entrypoint applies every
numbered file under migrations/ in order and records its SHA-256 checksum in
ai_team_schema_migrations. Concurrent replicas serialize migration startup;
editing an already-applied migration fails closed.
Retrieved memories are channel-scoped. Legacy or manually inserted
agent_memories rows with no metadata.slack_channel_id are excluded from
channel context by default; use the explicit "slack_channel_id": "*" marker
only for memory intentionally shared with every channel.
For an externally managed database, install the pgvector extension and give the
migration role permission to run CREATE EXTENSION IF NOT EXISTS vector, or
preinstall it as a database administrator. To apply migrations through the app
entrypoint before serving:
DATABASE_URL=postgresql://... CONFIG_PATH=my-config python -m ai_team.entrypointCONFIG_PATH/context-pack.md is a bootstrap seed. On startup, the service
inserts it into team_docs using the keys configured in team.yaml, only if
that doc does not already exist. Later edits to the bootstrap file do not
overwrite the live document; use an explicit update or reset the memory scope.
python -m venv .venv
. .venv/bin/activate
python -m pip install pip==26.1.2
python -m pip install --require-hashes -r requirements-dev.lock
python -m pip install --no-deps --no-build-isolation -e .
CONFIG_PATH=config/default python -m pytest -qThe published container installs the hashed requirements.lock; development
uses the hashed requirements-dev.lock. The .txt files and pyproject.toml
remain the human-maintained dependency inputs.
Run locally without Docker:
CONFIG_PATH=config/default uvicorn ai_team.main:app --reload --port 8080Running uvicorn directly is useful for tests against an already migrated
database. For a new database, run python -m ai_team.entrypoint once so the
migration gate executes.
See docs/architecture.md for runtime architecture, endpoints, storage, tools, deployment and roadmap details.
Politikkradar uses AI Team as one deployed configuration for Borge Labs. The framework itself is domain-agnostic: each organization supplies its own config, personas, repositories, memory rules and operating context.
In Borge Labs' own delivery loop, the deployed AI Team configuration handles the Slack-facing work: teammates triage requests, draft specifications, file and consume work-queue issues, and relay human approvals. Implementation runs in a separate supervised pipeline, not in this repository. A supervised multi-agent delivery loop describes that operating model.
The dogfooding case study describes what daily internal use did and did not validate without publishing private workspace content. See the research release notes for the bounded release scope.
There is no support SLA or committed roadmap. Read SUPPORT.md before deploying; forks are welcome, while issues and pull requests are handled best-effort.
python3 scripts/precommit_scan.py --allThe safety scan checks for credential-looking values and placeholder private keys. It is a lightweight guard, not a substitute for a dedicated secret scanner before publishing.
AI Team is built by Borge Labs, an independent Norwegian AI systems lab and product studio. It coordinates the AI staff behind our products and can hand approved coding jobs to its sibling project AI Dev Team, a developer-team runtime for supervised coding agents:
- Politikkradar - source-grounded monitoring of Norwegian politics for newsrooms and elected officials.
- Ordrett - verbatim Norwegian speech-to-text.
MIT. See LICENSE.