Skip to main content

Development guide

This page is the starting point for contributors extending VibeSys. It links to the focused guides for framework code, domains, skills, profilers, input bundles, and the TUI.

Before you change code

Repository layout

src/vibesys/ Python framework and loop implementation
clients/tui/ TypeScript terminal client and launcher
libs/ Reusable standalone libraries
examples/ Candidate repositories, tasks, and legacy input bundles
resources/evaluators/ Reusable versioned evaluator packages
resources/skills/ Bundled Agent Skills and reference material
resources/profilers/ Profiler MCP servers and support packages
docs/ Contributor and subsystem guides
tests/ Python and integration tests

The main framework boundaries are:

  • src/vibesys/loops/ owns the outer-loop policies and shared loop helpers.
  • src/vibesys/agents/ owns the agent-runner abstraction and integrations.
  • src/vibesys/domains/ owns domain-specific prompt context and hooks.
  • src/vibesys/backends/ owns compute and execution backends.
  • Candidate repositories own target-specific tasks and candidate contracts below .vibesys/tasks/. Legacy input bundles remain under examples/.
  • resources/evaluators/ owns reusable versioned evaluator packages.

Local development

Work from a source checkout

Install Python 3.12+, Git, and uv, then clone the repository. Optional local credentials and configuration can be copied from the provided examples:

cp .env.example .env
cp agent.toml.example agent.toml

uv run creates the Python environment automatically, so uv sync is not required before running commands. For example:

uv run vibesys --help
uv run vibesys validate examples/data-structures/repositories/queue-rs --task spsc
uv run pytest

To use the interactive TUI from a checkout, install Node.js 20+, Bun, and pnpm 11 (or enable Corepack). The launcher installs frontend dependencies and builds the client when needed.

For a headless installation directly from GitHub without a checkout:

python -m pip install "git+https://github.com/uw-syfi/vibesys.git"

GitHub source installs skip optional submodules and do not build the native TUI. Pass --headless to suppress the fallback notice. Use a supported PyPI wheel when you need the bundled TUI.

Tests and submodules

Repository submodules are opt-in. Initialize them only when your work needs the vendored sources, using --checkout to override their default update policy:

git submodule update --init --recursive --checkout

Run the Python checks from the repository root:

./scripts/check_format.sh
./scripts/check_lint.sh
uv run pytest

For a focused test, use for example:

uv run pytest tests/loops/plain/test_plain_loop.py
uv run pytest -k orchestrator

The TypeScript client has its own workflow; see clients/tui/README.md. The short version is:

pnpm install --frozen-lockfile
pnpm --dir clients/tui generate:protocol
pnpm --dir clients/tui check
pnpm --dir clients/tui test
pnpm --dir clients/tui build
pnpm check:ts

When Python protocol models change, regenerate the files under clients/tui/src/generated/ and review the diff.

Extend VibeSys

Use the guide that matches the surface you are adding:

The experimental Omnigent adapter is a developer-facing alternative to the standard CLI adapter. It currently supports Claude and Codex on the host path only; see the feature-flag guide before enabling it.

Keep target-specific APIs, ABIs, ownership rules, and service protocols in the task's CANDIDATE_CONTRACT.md or design documentation rather than in the neutral framework prompts.

Internal tools and workflows

The plain loop's issue MCP server is an internal development tool:

uv run vibesys-issue-mcp

For issue forms and repository issue conventions, see docs/issue-authoring.md. For evolutionary search policy work, see docs/openevolve.md.

CI gates

Every pull request must pass the following gates before it can be merged. You can run each one locally before pushing.

Format

./scripts/check_format.sh

Runs ruff format --check (whitespace, line length, blank lines) and ruff check --select I (import order) across src, tests, examples, resources, and libs. To auto-fix locally:

uv run ruff format src tests examples resources libs
uv run ruff check --select I --fix src tests examples resources libs

Lint

./scripts/check_lint.sh

Runs ruff check . across the whole repository. Fix automatically where possible with --fix; the remaining errors need manual attention. Test files that trigger false-positive rules (e.g. S106 on fixture arguments, ANN001/ANN201 on helpers, PLR0913 on builder functions) can suppress them with a file-level # ruff: noqa: <codes> comment at the top of the file.

Coverage

The test job enforces two independent coverage floors:

Repo-wide floor — 75 %
uv run pytest (with --cov already wired in via pyproject.toml) must reach 75 % combined statement + branch coverage across the tracked packages (vibesys, vs_feature_flags, vs_github, vs_issue_board, vs_loop_state, vs_project, vs_sandbox, and vs_bench).

Per-module floor — 40 %
scripts/check_coverage_floor.py reads coverage.json and rejects any module below 40 % that is not in the allowlist in [tool.vibesys.per_module_coverage] in pyproject.toml. The repo-wide average can mask a single near-zero module; this floor prevents that (see issue #298). Modules may be allowlisted only with a comment explaining why they are intentionally untested.

Patch coverage (PRs only)
New lines introduced by a pull request are checked separately against a patch-coverage threshold. If your PR adds code that is not exercised by any test, this gate will fail even if the repo-wide numbers are healthy. Add focused unit tests for the new code paths — prefer pure-function extraction (as in issue #290) to make new logic directly testable.

To reproduce the coverage check locally:

uv run pytest --cov-report=json
uv run python scripts/check_coverage_floor.py coverage.json