Contributing¶
Yeti is a Frostyard project. Contributions are welcome --- whether that's fixing a bug, adding a job, improving documentation, or just reporting an issue.
Development setup¶
Prerequisites:
- Node.js 22+
ghCLI (authenticated)claudeCLI (authenticated) --- needed to run integration-style tests manually
Getting started:
git clone https://github.com/frostyard/yeti.git
cd yeti
npm ci
npm run build
npm test
Development mode:
npm run dev
This runs the project with tsx for live TypeScript execution without a build step.
Project structure¶
src/
├── main.ts # Entry point, initialization, shutdown
├── scheduler.ts # Job scheduling engine
├── claude.ts # AI backend dispatch and worktree management
├── github.ts # GitHub API via gh CLI
├── github-app.ts # Optional GitHub App authentication
├── config.ts # Configuration loading and live reload
├── db.ts # SQLite database
├── server.ts # HTTP dashboard
├── discord.ts # Discord bot
├── notify.ts # Notification dispatcher
├── error-reporter.ts # Error deduplication and reporting
├── jobs/ # One file per job
│ ├── issue-refiner.ts
│ ├── plan-reviewer.ts
│ ├── issue-worker.ts
│ ├── ci-fixer.ts
│ ├── auto-merger.ts
│ ├── review-addresser.ts
│ ├── doc-maintainer.ts
│ ├── improvement-identifier.ts
│ ├── issue-auditor.ts
│ ├── repo-standards.ts
│ ├── triage-yeti-errors.ts
│ ├── mkdocs-update.ts
│ └── prompt-evaluator.ts
├── pages/ # Dashboard HTML builders
└── test-helpers.ts # Test factories
scripts/
└── ab-agent-test.sh # A/B test harness comparing AI backends
Testing¶
Tests are co-located with source files (*.test.ts next to the module they test). Run them with:
npm test # all tests
npx vitest run src/scheduler.test.ts # single file
npx vitest run -t "returns ms until" # by name pattern
npm run test:watch # watch mode
Testing conventions:
- External boundaries are mocked:
ghCLI,claudeCLI, filesystem operations. - Use
vi.mock()at module level for mocking. - Test helpers in
src/test-helpers.tsprovide factories:mockRepo(),mockIssue(),mockPR(). - TDD is the expected workflow --- write a failing test, then implement.
Making changes¶
-
Create a branch from
main:git checkout -b feat/your-feature -
Write tests first --- Yeti uses TDD. Start with a failing test that describes the behavior you want.
-
Implement the change --- make the test pass.
-
Check everything builds:
npm run build npm test -
Consider cross-cutting concerns:
- Changes to
src/config.ts? Updatedeploy/install.shandsrc/pages/config.ts. - Changes to job behavior? Update
src/pages/dashboard.tsandsrc/pages/queue.ts. - New API routes? Update
src/pages/accordingly. - New or changed config fields? Add form controls in
src/pages/config.ts.
- Changes to
-
Update documentation --- update
CLAUDE.md,README.md, and relevant files inyeti/andsite/.
Adding a new job¶
Jobs follow a consistent pattern. Each job:
- Exports a
run()function - Is registered in
main.ts - Must be listed in
enabledJobsto activate
Steps to add a job:
- Create
src/jobs/your-job.tswith arun()export. - Create
src/jobs/your-job.test.tswith tests. - Register the job in
src/main.tswith the scheduler. - Add the interval/schedule config to
src/config.ts. - Add the job name to the type definitions.
- Update the dashboard pages if the job introduces new queue categories or states.
- Add documentation in
site/reference/jobs/your-job.mdand updatesite/reference/jobs/index.md. - Update
mkdocs.ymlnav to include the new job page.
Commit conventions¶
Yeti uses conventional commits:
feat: add new capability
fix: resolve a bug
refactor: restructure without behavior change
docs: documentation only
test: test additions or changes
chore: build, CI, or tooling changes
Keep commit messages concise. The PR description is where detail belongs.
Release process¶
Releases are automatic. When changes land on main:
- The release workflow creates a version tag:
v<YYYY-MM-DD>.<N> - A release tarball is built:
dist/+deploy/+node_modules/ - The tarball is published as a GitHub release
- Deployed instances pick up the release via the auto-updater within 60 seconds
Code style¶
- TypeScript with strict mode enabled
- ESM modules (
"type": "module"in package.json) - No default exports
- Prefer
constoverlet, nevervar - Error handling at boundaries, not defensively everywhere
- Keep files focused --- if a file is growing past a few hundred lines, consider splitting
Reporting issues¶
Found a bug or have a feature idea? Open an issue on the GitHub repository.
For bug reports, include:
- What you expected to happen
- What actually happened
- Relevant log output (
journalctl -u yeti -n 100 --no-pager) - Your Yeti version (
curl localhost:9384/status | jq .version) - Your
enabledJobsconfiguration