Skip to content
Agentmart
Submit a tool

AGENTS.md · juggler-ai/juggler

AGENTS.md from juggler-ai/juggler: 309 lines covering Build / Test / Lint / Dev, Linting, Tests, Git commits and more.

Template by juggler-ai

IndexedAGPL-3.0★ 804
Write a review

Install

Works with Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code. Read the repository before you give any tool access to your data.

curl -fsSL https://raw.githubusercontent.com/juggler-ai/juggler/develop/AGENTS.md -o AGENTS.md

Read it and adapt it to your project before use.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

The AGENTS.md file that juggler-ai/juggler (804 stars) keeps for coding agents. It has 309 lines in 11 sections: Build / Test / Lint / Dev; Linting; Tests; Git commits; Changelog; Conventions; Architecture; Web UI; Debugging the viewer; Paths; Vendored forks. Use it as a model for your own project's instructions.

Use cases: code-generation, testing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

What's in it

An AGENTS.md file: instructions coding agents (Codex, Cursor, Copilot, Gemini CLI and others) read before working in a repo.

For
Codex, Cursor, GitHub Copilot, Gemini CLI, OpenCode, Claude Code
Length
309 lines
File
AGENTS.md

Sections

  1. Build / Test / Lint / Dev
  2. Linting
  3. Tests
  4. Git commits
  5. Changelog
  6. Conventions
  7. Architecture
  8. Web UI
  9. Debugging the viewer
  10. Paths
  11. Vendored forks

First lines (shown under the repo's AGPL-3.0 license)

# Juggler

## Build / Test / Lint / Dev

```bash
make build          # Lint + build Go binaries (bin/juggler, bin/juggler-app, bin/juggler-test)
make test           # All tests (unit + integration + browser); RUN='<name>' runs one
make go-build       # Build Go binaries only (skip linting)
make test-full      # Lint + tests. Run before opening a PR.
make lint           # All linters (Go + JS + CSS) — the only way to lint everything
make fix            # Auto-fix what the linters can (gofmt, eslint/stylelint --fix); then re-lint
make dev            # Build and run server
make build-windows  # Cross-compile bin/windows/*.exe (pure-Go, no cgo)
```

`make test-full` (lint, build and every test) **must** pass before any task is
complete; iterate with `make test RUN='<name>'`. `make build` is for launching
the app — `make test` already builds everything it tests.

### Run them in the foreground

They are ordinary commands that take a few minutes (`make test` is typically
3–6). Run the bare command with a timeout long enough to cover it — 20 minutes
— and wait for it to finish.

**Never** start a build or test run as a background task, poll it, watch it
with a monitor, wait on its pid, or loop until the process exits. It gains nothing: you get the identical
output several turns later, having spent those turns guessing an interval —
too short burns turns, too long stalls the task, and "wait for the process to
disappear" wedges on the first thing that outlives it. If a run genuinely
exceeds the timeout, that is a hang worth reporting, not a reason to relaunch
it detached.

**Never pipe them through `tail`, `head`, `grep` or `tee`, redirect them to a
file and read it back, or append `|| true`.** The output is already the summary (see Tests below), and `tail` is the worst choice of the
lot: a failure is written top-down, so truncating to the tail keeps the summary
line you already had and cuts the assertion that says what broke.

## Linting

- **`make lint` and `make lint-files` are the only sanctioned ways to lint.**
  Never invoke `golangci-lint`, `go vet`, `gofmt`, `eslint`, or `stylelint`
  directly — every config, flag, ignore pattern, and pinned tool version lives
  in the `Makefile` / `scripts/lint-files`, and a hand-rolled invocation
  silently diverges from what CI enforces.
- To lint specific files (routed by extension to the same linters):
  ```bash
  make lint-files FILES="cmd/juggler/worker/foo.go web/js/bar.js"
  ```
- **Before fixing lint failures by hand, run `make fix`** — it applies every
  auto-fix the linters can (gofmt, `golangci-lint --fix`, `eslint --fix`,
  `stylelint --fix`) using the same configs and globs as `make lint`, then tells
  you to re-lint. It never fixes type errors (lint-types), dead code
  (lint-deadcode), or missing imports in the docs' JavaScript examples
  (lint-docs) — those still need a human. `make fix` and `make fix-files`
  are the only sanctioned ways to auto-fix; don't run `gofmt -w`, `eslint --fix`,
  or `stylelint --fix` directly (same drift reason as lint). Per-file:
  ```bash
  make fix-files FILES="cmd/juggler/worker/foo.go web/css/bar.css"
  ```

## Tests

- `make test` runs the whole suite (Go unit + integration + browser) without
  `-v`, so its output already is the summary: one `ok <pkg> <time>` line per
  passing package, and on failure only the failing tests' own output. Each layer
  announces itself, the first failing layer stops the run — so a failure is the
  last thing on screen — and a `✗` line under it names the layer. The same text
  is teed to `bin/test*.log` purely for afterwards; the log and the terminal
  hold the same thing, so there is nothing to tail or grep.
- **To run one specific test, pass `RUN='<regex>'`** — a `go test -run` pattern
  matched against test-function names. It also turns on `-v` so you see that
  test's own output, and silences the packages that hold no matching test (which
  under `-v` would otherwise announce themselves and bury the one you asked
  for). This is the sanctioned way to iterate on a single test;
  **don't run `node`, the browser harness, or `go test` by hand** — the target
  builds the right binary, sets the flags CI uses, and tees the log for you.
  ```bash
  make test RUN='TestDiffView'            # one test, whichever layer it's in
  make test RUN='TestDiffView/collapsed'  # one subtest
  make test-go RUN='TestWorker'           # restrict to the fast unit layer
  ```
- Browser tests launch `bin/juggler-testsrv --assets-from-disk`, serving the
  local `web/` tree. That is the test-capable server `make test` builds beside
  the app (`make test-build` on its own), stamped `-test` so a server a suite
  spawned says so when it talks to the update endpoint; `bin/juggler` stays the
  app you launch. Once it exists, web-only edits don't need a rebuild — rerun
  `make test RUN='<name>'` (Go builds are incremental, so this is cheap).
  Rebuild only for Go / embedded-asset / build-file changes.
- Browser-test lanes share one offscreen pool window. They do not reliably paint,
  so a test must not await `requestAnimationFrame` or a post-layout
  `ResizeObserver` delivery; exercise a synchronous seam instead. Lane viewport
  width also varies by platform and may cross the 36rem phone breakpoint, so
  geometry that depends on a breakpoint belongs in an explicitly sized iframe.
- rAF delivery in a lane is platform-split: frames never arrive on macOS or
  Linux (WebKitGTK), but Windows (WebView2) delivers them — so product code
  deferred through `requestAnimationFrame` is exercised only on Windows CI.
  Test such behaviour by calling the deferred function directly.
- The pool is `JUGGLER_TEST_WINDOWS` subprocesses x `JUGGLER_TEST_IFRAMES` lanes,
  and the lanes inside one subprocess share a single content process — one JS
  heap, one main thread. Raising iframes while dropping windows to 1 serialises
  the suite onto that thread and produces cascades of arbitrary timeouts.
- **A lane is an iframe, and the lanes in one window share a single session
  history.** A `pushState` or `back()` in any lane traverses that joint history
  and delivers the `popstate` to whichever lane's entry it popped — so one lane
  closing a menu could dismiss the overlay another lane had just opened. Nothing
  in a lane may touch `window.history` casually: the overlay Back-button
  sentinel (`popup-manager.js`) stands down unless the app owns the history
  (`window.top === window`), and the two suites that test it switch it on for
  their own duration via `__setBackIntegrationForTests` while stubbing the
  History API. **A test must never traverse the real one**, however carefully it
  balances its own entries: a sibling lane loading its next test page puts an
  entry on top of the shared stack, so the `back()` lands on the sibling — which
  is sent back a document — and this lane is delivered no `popstate` at all. A
  stub answering with a `popstate` of its own, in a later task, reproduces
  everything a real traversal was there to show.
- **Model limits go stale silently. `TestCatalogDrift` is how you find out.**
  Providers publish new models and retire old ones constantly, and a wrong
  context window has no symptom — the model works and merely compacts far
  sooner than it needed to. The audit compares what each provider serves right
  now against what the built-in catalogs say, using whatever keys you have
  configured, and names the providers it had to skip:
  ```bash
  JUGGLER_MODELS_AUDIT=1 make test-go RUN='TestCatalogDrift'
  ```
  It is opt-in (one network call per provider) and skipped in `make test`. Run
  it after any vendor announcement, and before a release. The no-network half,
  `TestCatalogInvariants`, runs every time and checks every catalogued model for
  limits that cannot be right.
- Suite timings are load-sensitive. A browser test that fails in a full run and
  passes alone is not a regression in the code it asserts on — re-run the exact
  subtest in isolation before investigating it. It is not automatically "just
  load" either: that shape has twice turned out to be a real harness fault that
  only a busy machine reaches.
- **Every wait in a test rides the per-test deadline** (`budgetFor` /
  `deadlineFor` in `web/js-tests/utilities/test-deadline.js`), never a bare
  nominal timeout of its own. A number chosen when a lane had the pool to itself
  measures the pool rather than the code once nine lanes share a machine.
  `unit:test-budget` asserts this contract; add a case to it when you add a wait.
- A wait whose expiry does not itself fail the test — one that answers a dialog
  or a prompt something else is blocked on — must record why it gave up. Silence
  there turns a missed deadline into a hang that gets reported much later,
  against whatever was in flight at the time.

## Git commits

- Commit messages: **one line, minimal, past tense**
  (e.g. `Fixed cross-conversation cancel leak`).

## Changelog

- Add entries under `[Unreleased]` in `CHANGELOG.md` as you make user-facing
  changes; release tooling rolls that section into a dated version section when
  a release is cut.
- **Each release is a single flat list of changes** — no `Added`/`Changed`/
  `Fixed` subsection headers.
- **Entries are terse one-liners**: ~12 words, the user-visible headline only.
  Match the length of the existing entries.

## Conventions

Signals

Stars
804
Forks
55
Open issues
12
Last commit (this folder)
Oct 19, 2026 (9 days ago)
Last release
Oct 23, 2026 (5 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
AGPL-3.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from juggler-ai

Cite this page

AGENTS.md · juggler-ai/juggler. Agent Mart. https://agentmart.dev/templates/juggler-ai-juggler-agents-md (last updated 2026-10-24)