Skip to content

Repositories

Every Yak task targets exactly one repository. This guide covers how to add repos, what the automatic setup task does, how repos get routed to, and how to customize per-repo behavior through CLAUDE.md.

Go to https://{your-domain}/repos/create and fill in the form. Yak clones the repo using the GitHub App’s installation token and automatically dispatches a setup task — Claude Code reads the repo’s README and CLAUDE.md, sets up the dev environment, and verifies everything works.

The form has three sections:

SectionFields
BasicsSlug (auto-generated from name, editable), display name, Git URL (HTTPS clone URL), path on disk (auto-filled from slug), default branch, active toggle, default toggle
IntegrationCI system (github_actions or drone), Sentry project slug (optional)
NotesFree-text operational notes. Shown only in the dashboard — never sent to Claude.
  • slug must be unique across all repos
  • path must be an absolute filesystem path (typically /home/yak/repos/{slug})
  • At most one repo can have is_default = true. Toggling default on a new repo clears it from any other.

When a repo is first added, Yak dispatches a one-time setup task — a Claude Code session that bootstraps the dev environment. This task has mode = setup and runs on the yak-claude queue like any other task.

  1. Reads README.md, CLAUDE.md, docker-compose.yml, and other config files
  2. Sets up the dev environment:
    • docker-compose up -d
    • Installs dependencies (composer install, npm install, pip install, etc.)
    • Runs migrations and seeders
  3. Verifies the environment works by starting the dev server and running the test suite
  4. Reports success or failure with details of what was set up

After setup completes successfully, the sandbox container is snapshotted using ZFS copy-on-write. This snapshot becomes the base image for all future tasks on this repo.

When a task starts, Incus clones the snapshot in ~2 seconds — the clone includes the fully-prepared dev environment (Docker images pulled, dependencies installed, database migrated). Each task gets its own isolated copy; changes never leak between tasks.

This means:

  • No cold-start penalty — every task starts from the prepared snapshot.
  • No shared state corruption — each task has its own filesystem, Docker daemon, and network.
  • Concurrent execution — multiple tasks for the same repo can run in parallel from the same snapshot.

The repo’s setup_status column tracks progress:

StatusMeaning
pendingRepo was added but setup has not started yet
runningSetup task is currently executing
readySetup completed successfully — repo is ready for tasks
failedSetup failed. Check the setup task’s detail page for logs.

The repo list in the dashboard shows this as a colored badge.

If the dev environment breaks (new Docker services, migration changes, dependency updates), re-run the setup task:

  • Dashboard: click Re-run Setup on the repo’s edit page
  • CLI: docker exec yak php artisan yak:setup-repo my-app

Re-running setup tears down the old environment and brings up a fresh one.

Every task targets exactly one repo. When a task arrives, Yak detects the target using this priority chain:

  1. Explicit mention@yak in my-cli: ..., --repo=my-cli, repo: my-cli
  2. Sentry project mapping — the sentry_project column on repositories matches the incoming Sentry project slug
  3. Default repo — falls back to whichever repo has is_default = true

Only active repos (is_active = true) are considered. Inactive repos are skipped entirely, including their Sentry mappings.

One repo per task, always. If a request mentions multiple repos — for example, “audit cron jobs across app and api” — the routing layer creates separate tasks, one per repo. Each task runs independently and posts its own results.

If a Slack task has no explicit in {repo}: mention, no Sentry mapping, and multiple active repos exist, the task enters awaiting_clarification with repo options before any Claude Code work begins. This avoids wasting an Opus run on the wrong codebase. If only one active repo exists, it’s always the right one and no clarification is needed.

Linear and Sentry tasks never clarify — Linear falls back to the default repo, Sentry requires an explicit mapping.

CLAUDE.md — The Highest-Leverage Config Point

Section titled “CLAUDE.md — The Highest-Leverage Config Point”

Every repo should have a CLAUDE.md at its root. This file is loaded by Claude Code for every task and is the single most important customization point — it’s how you teach Yak the conventions, patterns, and landmines specific to your codebase.

A good CLAUDE.md reduces rework and bad PRs more than any other change you can make.

  • Project structure — where controllers, models, tests live; which directories are off-limits
  • Code conventions — naming, type hints, docblock style, preferred patterns
  • Test patterns — test framework, factory usage, how to run a single test, what tests to run for a given file
  • Do-not-touch list — vendored files, generated code, migration files from past releases, packages you don’t own
  • Known quirks — environment setup steps, hidden dependencies, services that must be running
  • Dev environment — how to start the dev server, default ports, how to seed test data, how to log in with a test user for visual capture
CLAUDE.md
## Project Structure
- app/Http/Controllers/ — HTTP controllers; one invokable per action
- app/Services/ — external API clients and business services
- app/Models/ — Eloquent models; use factories in tests
- tests/Feature/ — feature tests (RefreshDatabase enabled globally)
## Conventions
- Use single quotes unless interpolation is needed
- Explicit return types on all methods
- Pest for tests — no PHPUnit class syntax
## Testing
- `vendor/bin/pest --compact --filter={name}` for a single test
- For controller changes, run `tests/Feature/Http/` only
- Full suite runs on CI, not locally
## Do Not Touch
- app/Legacy/ — scheduled for deletion in Q2
- database/migrations/2019_* — frozen, don't amend
- lib/vendor-patches/ — maintained by hand
## Dev Environment
- `docker-compose up -d` brings up mysql, redis, meilisearch
- App runs at http://localhost:8000 after `php artisan serve`
- Test user: test@example.com / password (seeded via DatabaseSeeder)

Treat CLAUDE.md as a living document. Every bad Yak PR is a signal that CLAUDE.md needs a new rule. When a reviewer rejects a PR for a convention Yak should have known, add that convention to CLAUDE.md — the next task won’t repeat the mistake.

Shows all configured repos with slug, name, CI system, setup status badge, active/inactive state, default flag, and task counts (total and last 7 days). Click a row to edit.

The three-section form described above. After save, the setup task is auto-dispatched and the repo’s setup status transitions from pendingrunning.

Same form pre-filled with current values. Also includes:

  • Re-run Setup button — re-dispatches the setup task
  • Deactivate toggle — soft-disables the repo (historical tasks remain; new tasks will not route here)
  • Delete (danger zone) — only available if the repo has zero tasks. If the repo has any task history, you must deactivate instead.

Each repository has four deployment-related fields:

  • deployments_enabled (bool, default false). Flip to true to wire PR events on this repo to the preview deployment pipeline.
  • preview_manifest (json). Authored by SetupYakJob; editable in the dashboard. See branch-deployments.md for the shape.
  • preview_env_overrides (json, optional). Symbolic names of env vars to inject from Ansible vault at container start time. Use this for per-repo API keys that production-like previews need.
  • current_template_version (int). Bumped each time SetupYakJob re-seeds the template. New deployments clone from this version; existing deployments stay pinned to their birth version until an operator rebuilds them.

Each repo has a PR Review toggle on its edit page. When enabled, Yak reviews every open, non-draft PR on the repo — posting line-level comments with category + severity + (sometimes) suggestion blocks. See the PR Review guide for the full flow.

Path filters let you narrow what Yak reviews. The defaults (in config/yak.php) exclude vendor/**, node_modules/**, lockfiles, and minified assets; per-repo overrides are a chip list on the same edit page.

Yak automatically runs git fetch origin {default_branch} every 30 minutes via the scheduled yak:refresh-repos command. This keeps each repo’s default branch tip up to date so that new tasks start from the latest code without a manual pull.

The repositories table is deliberately minimal — just slug, name, path, default branch, CI system, Sentry mapping, and notes. Everything else is auto-detected at task time:

ThingWhere it comes from
Language / frameworkREADME.md, CLAUDE.md, and file inspection by Claude Code
Test commandsCLAUDE.md and composer.json / package.json scripts
Dev server commandCLAUDE.md and docker-compose.yml
Dependency install commandsCLAUDE.md and detected package managers
Test credentials for visual captureCLAUDE.md, seeder files, or .env.example

This is intentional: different repos have very different setups, and forcing them all into a single database schema would be brittle. CLAUDE.md is the one file you maintain — and because it lives in the target repo, it travels with the code and is version-controlled by the team that owns it.