Compare commits
10 Commits
df575129a1
...
feat/66-wi
| Author | SHA1 | Date | |
|---|---|---|---|
| 644a77b0cb | |||
| f1fa65ebc2 | |||
| dda7f8d3dd | |||
| a712f2c186 | |||
| 2fb1036329 | |||
| 5d7c76d797 | |||
| c613927fb4 | |||
| c75e4ef4f3 | |||
| 4f49b2a249 | |||
| 058fb5b748 |
@@ -15,6 +15,8 @@ This file carries only what applies to **every** session. Setup, prerequisites,
|
||||
|
||||
Not everything in a plugin root is generated. `README.md`, `docs/`, `bin/`, `sources.md`, `.mcp.json` and per-plugin extras are hand-authored there with no `.apm/` source — edit those in place. The rule is per-path, not per-directory. But a file placed *inside* a mirrored directory is deleted on the next sync (`sync_dir` runs `rm -rf` before every copy), so plugin-root documentation goes in `docs/`, never in `hooks/` or `skills/`.
|
||||
|
||||
`.mcp.json` is hand-authored but it is **not** outside apm. MCP is a first-class apm primitive, and a plugin's `.mcp.json` is how this repo declares one: apm reads the `mcpServers` pointer in the generated `.github/plugin/plugin.json`, resolves it to `.mcp.json`, and injects the result into that package's `dependencies.mcp` when a consumer installs it. Declare MCP servers there and **never** in the plugin's own `apm.yml` — that arms a per-package gate this repo cannot satisfy (`LESSONS.md`, 2026-09-12).
|
||||
|
||||
Full model: `docs/spec/architecture.md`.
|
||||
|
||||
## Prefer plugin skills over raw shell
|
||||
@@ -36,11 +38,7 @@ Fall back to raw shell only when no skill covers it.
|
||||
- **Do not add repo-owned keys to `.claude/settings.json`.** apm treats it as its own deployed artifact and `apm audit --ci` replays the install and diffs, so anything apm would not have written is permanent drift that fails the `apm-audit-ci` pre-push hook. A hook you want here is authored in `plugins/<name>/.apm/hooks/` and deployed by apm, never hand-written into that file. The `SessionStart` entry already in it is exactly that: kyberforge authors it in `plugins/kyberforge/.apm/hooks/hooks.json` and apm merges it in, so it is apm's own output, it is what the replay expects, and it belongs in the commit — do not strip it (ADR-0019). Machine-specific settings go in the gitignored `.claude/settings.local.json`; shared enforcement goes in `.pre-commit-config.yaml`.
|
||||
- **`apm.lock.yaml` turning up modified is expected, not a bug.** kyberforge's `SessionStart` hook runs `apm outdated` at startup and `apm update --yes` when something is behind, which rewrites the lock. Commit or discard it deliberately.
|
||||
- **A `.apm/` edit is not live in this session until it is pushed.** The six dependencies resolve from the holocron remote, unpinned against the default branch. `apm install` deploys from the lock; `apm update` is what re-resolves refs.
|
||||
- **The ADR-0020 skill gates ship hot, with no baseline — and the corpus is now clean.** All 39 skills clear both FAIL tiers: no description over 400 characters, no body over 900 words (counted body-only). Retrofitted plugin by plugin under #99 (see `docs/spec/gates.md`). Because nothing is grandfathered, the gates now bite on first commit — a new skill, or an edit that pushes a description past 400, is blocked until it complies. **No routing target dangles**, and `tests/test-adr0020-targets.sh` pins that set as empty, so a new boundary clause naming a non-existent skill fails the suite rather than joining a backlog. Two blind spots survive: `skill-size-check` does not cover the Vale half, so `Kyberforge.CompositionNote` fires nowhere today but any new description can reintroduce it; and no `references/` file is linted by anything, so prose relocated out of a body to satisfy the word gate lands outside the prose gate. It has two independent causes and closing either alone changes nothing — `docs/spec/gates.md` has both, issue #117 tracks it. Check both gates: `pre-commit run --all-files`.
|
||||
- **Run `bash tests/run-tests.sh --strict` before considering any change done.** Keep the flag: without it a suite whose dependency is missing exits 77 and is counted SKIPPED rather than failed, so the run goes green having verified less than it claims.
|
||||
- **Before pushing, rehearse the gate locally:** `pre-commit run --hook-stage pre-push --all-files`. It runs the 14 pre-push hooks this repo authors itself plus pre-commit's 2 `meta` hooks, so it prints 16; `check-release-needed` passes without checking anything, because it needs a real push to `main`. `docs/spec/gates.md` reconciles both.
|
||||
- **Pushing without a network** needs `SKIP=apm-marketplace-check,apm-pack-check-clean git push` — those two resolve a remote marketplace entry via `git ls-remote`. Skip only those two; the rest are real local checks, and adding one to `SKIP` disarms it silently.
|
||||
- **Author commits with `git-commits`** — it validates Conventional Commits, which `commit-msg` enforces.
|
||||
- **This repo and Gitea are the only source of truth.** All project state, decisions, and working conventions live here. Do not use an external memory system for this project — cached state diverges from the repo and you get a split brain. Before answering any design or architecture question, check `docs/adr/` for an existing decision.
|
||||
|
||||
## Key documents
|
||||
|
||||
@@ -10,6 +10,14 @@ Patterns observed during development of this repo. Three or more entries on the
|
||||
|
||||
---
|
||||
|
||||
## 2026-09-12 — "Not an `.apm/` primitive" was read as "not an apm primitive", and the review that followed was wrong
|
||||
|
||||
`AGENTS.md` and `docs/spec/architecture.md` both listed `.mcp.json` alongside `README.md`, `docs/` and `bin/` as plugin-root material "hand-authored with no `.apm/` source". That is literally true — nothing under `.apm/` produces MCP config — but it reads as "apm has no MCP concept", and a review of PR #132 drew exactly that conclusion and recommended moving the declaration into the plugin's `apm.yml` under `dependencies.mcp`. The recommendation was wrong twice over. It arms `lockfile-exists` in the per-package `apm audit --ci` that the `apm-audit-ci` hook runs in every `plugins/*/`, which then demands the package's whole deployed tree inside the package directory: 93 missing files and 79 drifted paths on `plugins/gitea`. And it was unnecessary, because the `.mcp.json` route already reaches `dependencies.mcp` through the `mcpServers` pointer in the generated Copilot manifest, env references intact.
|
||||
|
||||
Two process lessons, not one. First, when a doc says a file is not a primitive **of a specific subsystem**, say which subsystem and what the file actually is instead — the negative claim alone invites the wrong generalisation. Second, the three scratch installs that produced the wrong conclusion all used local `./path` dependencies, where apm skips the plugin-normalisation step that injects `.mcp.json`. The repo consumes its plugins as `git:` + `path:` objects. A scratch test that does not reproduce the real dependency form can invert the result, so reproduce the form, not just the shape.
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-17 — Workflow documents should prescribe sub-agent usage, not just allow it
|
||||
|
||||
When writing workflow documents (like `docs/notes/skill-implementation-workflow.md`), the natural tendency is to describe steps at a high level and leave sub-agent usage as an implementation detail. But if the workflow doesn't explicitly prescribe "spawn a sub-agent here," practitioners default to doing everything in the main context — accumulating token cost and losing the isolation benefit. Fix: make sub-agent usage a named step in the workflow, specifying what the agent receives, what it returns, and why it's isolated. This makes the workflow reproducible rather than dependent on the practitioner remembering to use agents.
|
||||
|
||||
11
README.md
11
README.md
@@ -35,6 +35,17 @@ Install all of these before setting up. Each one is a hard dependency of a git h
|
||||
| `python3` + PyYAML | Required by `scripts/skill-size-check.sh` (the `skill-size-check` pre-commit hook), which reads folded YAML frontmatter | `python3` is usually present — pre-commit is itself a Python application. `pip install pyyaml` if the hook reports PyYAML missing |
|
||||
| `vale` | Required by the `vale-audit-prefilter-skill` / `-agent` pre-commit hooks and the `check-vale-style-sync` pre-push hook | `brew install vale` (macOS), `snap install vale` (Linux), `choco install vale` (Windows), or https://vale.sh/docs/vale-cli/installation/ |
|
||||
| `claude` CLI | Required by the `validate-plugins` and `validate-marketplace` pre-push hooks | Claude Code |
|
||||
| `go` toolchain | The gitea MCP server runs as `go run gitea.com/gitea/gitea-mcp@v1.7.0`, resolved from `PATH`. Without it the server fails to start and every `gitea-*` skill loses its tools | https://go.dev/dl/ — verify with `go version` |
|
||||
|
||||
The gitea MCP server additionally needs two environment variables in the shell that launches your agent — referenced as `${GITEA_ACCESS_TOKEN}` and `${GITEA_HOST}` in `plugins/gitea/.mcp.json`, with apm passing those references through to the deployed config unexpanded so the values are resolved at server startup and never committed. Copy `plugins/gitea/.env.example` to `.env` at the repo root, fill in real values, then export it — nothing in this repo auto-loads a `.env` file:
|
||||
|
||||
```bash
|
||||
cp plugins/gitea/.env.example .env
|
||||
$EDITOR .env
|
||||
set -a; source .env; set +a
|
||||
```
|
||||
|
||||
Generate the token in Gitea under Settings, Applications. Scope it to the repositories you want the agent to reach. If the server starts but every call returns an authorization error, that token is the first thing to check.
|
||||
|
||||
Two notes worth reading before you skip one:
|
||||
|
||||
|
||||
@@ -49,6 +49,13 @@ Two compilers produce the plugin roots you see in the tree:
|
||||
|
||||
`.apm/` is the sole hand-edited authoring source for plugin content. An edit made in the flat mirror is discarded by the next sync and is reported as drift by the `check-plugin-content-sync` pre-push hook. Hand-authored material that is not an `.apm/` primitive — `README.md`, `docs/`, `bin/`, `sources.md`, `.mcp.json`, and per-plugin extras such as `plugins/git/config.example.json`, `plugins/gitea/references/` and `plugins/bin/evals/` — lives at the plugin **root** and is untouched by either compiler.
|
||||
|
||||
`.mcp.json` is the one entry in that list that is still load-bearing for apm rather than merely ignored by it. MCP is a first-class apm primitive — `dependencies.mcp` sits beside `dependencies.apm` in the manifest schema, and apm tracks deployed servers in `apm.lock.yaml` under `mcp_servers`, `mcp_configs` and `mcp_config_provenance`. A plugin reaches that primitive indirectly. `apm pack` writes the string `".mcp.json"` into the generated `.github/plugin/plugin.json` as its `mcpServers` value, and on install apm resolves the plugin manifest in the order `plugin.json`, `.github/plugin/plugin.json`, `.claude-plugin/plugin.json` — so the Copilot manifest wins, the pointer is followed, and `.mcp.json` is injected into the package's `dependencies.mcp` with any `${VAR}` env references intact. Verified against the real remote: a git-sourced install of `plugins/gitea` deploys the gitea server with both env references unexpanded.
|
||||
|
||||
Two consequences follow, and both have bitten already:
|
||||
|
||||
- **Do not declare `dependencies.mcp` in a plugin's own `apm.yml`.** It is the schema-correct place and it breaks the build. The `apm-audit-ci` pre-push hook runs `apm audit --ci` inside every `plugins/*/`, so a declared dependency arms `lockfile-exists` there, which then demands an `apm.lock.yaml` in the package plus every file of that package's own deployed tree present inside the package directory. Measured on `plugins/gitea`: 93 missing deployed files and 79 drifted paths.
|
||||
- **`.claude-plugin/plugin.json` carries an env-stripped copy.** `apm pack` inlines `.mcp.json` there, and its sanitiser drops `env` and `headers` blocks unconditionally at any depth, `${VAR}` indirection included. That copy is inert under apm, which never reaches it, but a native Claude Code plugin install reads exactly that file and would launch the server with no credentials. Anything installed natively rather than through apm needs its MCP env supplied by the host.
|
||||
|
||||
That immunity is positional, not by filename. Anything placed *inside* a mirrored directory is destroyed regardless of what it is: `sync_dir` runs `rm -rf "$dst"` before every copy, and `sync_hooks_json` does the same to `hooks/`. A hand-written `README.md` under `plugins/<name>/hooks/` or `plugins/<name>/skills/` is deleted by the next sync with no drift report, because a file with no `.apm/` counterpart is simply absent from the regenerated tree. This has already cost the repo one document — `plugins/kyberforge/hooks/README.md`, since restored to `plugins/kyberforge/docs/hooks.md`. Plugin-root documentation belongs in `docs/`.
|
||||
|
||||
## Governance layer
|
||||
|
||||
@@ -33,5 +33,5 @@ Describe the plan or design. Expect questions one at a time, each with a recomme
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The interview instruction plus the domain-awareness rules: file layout discovery, the five during-session behaviours, and the three-part ADR test |
|
||||
| `CONTEXT-FORMAT.md` | Skill-root document, cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `ADR-FORMAT.md` | Skill-root document, cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
| `references/context-format.md` | Cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `references/adr-format.md` | Cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
|
||||
@@ -76,7 +76,7 @@ When the user states how something works, check whether the code agrees. If you
|
||||
|
||||
### Update CONTEXT.md inline
|
||||
|
||||
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).
|
||||
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [context-format.md](references/context-format.md).
|
||||
|
||||
Don't couple `CONTEXT.md` to implementation details. Only include terms that are meaningful to domain experts.
|
||||
|
||||
@@ -88,6 +88,6 @@ Only offer to create an ADR when all three are true:
|
||||
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
|
||||
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
|
||||
|
||||
If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
|
||||
If any of the three is missing, skip the ADR. Use the format in [adr-format.md](references/adr-format.md).
|
||||
|
||||
</supporting-info>
|
||||
|
||||
@@ -10,7 +10,7 @@ Looks for places where a codebase is hard to understand, hard to test, or hard f
|
||||
2. **Present candidates.** A numbered list, each with files, problem, solution and benefits — benefits stated in terms of *locality* and *leverage* and of how tests would improve. No interfaces are proposed yet; the user picks one.
|
||||
3. **Grilling loop.** Walks the design tree for the chosen candidate, with documentation side effects landing inline as decisions crystallise.
|
||||
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `LANGUAGE.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `references/language.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
|
||||
ADRs are treated as decisions not to be re-litigated. A candidate that contradicts one is surfaced only when the friction is real enough to warrant reopening it, and is marked as such.
|
||||
|
||||
@@ -31,6 +31,6 @@ Point at a codebase or an area of one. Expect a numbered candidate list and a "w
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Condensed glossary, key principles, and the three-stage process |
|
||||
| `LANGUAGE.md` | Skill-root document, cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `INTERFACE-DESIGN.md` | Skill-root document, read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `DEEPENING.md` | Skill-root document, cited from `INTERFACE-DESIGN.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
| `references/language.md` | Cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `references/interface-design.md` | Read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `references/deepening.md` | Cited from `references/interface-design.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
|
||||
@@ -33,7 +33,7 @@ Key principles:
|
||||
- **The interface is the test surface.**
|
||||
- **One adapter = hypothetical seam. Two adapters = real seam.**
|
||||
|
||||
If a term or principle above is ambiguous in the case in front of you, or you need the definitions and the principles the two lists leave out, read `LANGUAGE.md`.
|
||||
If a term or principle above is ambiguous in the case in front of you, or you need the definitions and the principles the two lists leave out, read `references/language.md`.
|
||||
|
||||
This skill is _informed_ by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
|
||||
|
||||
@@ -74,7 +74,7 @@ Once the user picks a candidate, drop into a grilling conversation. Walk the des
|
||||
|
||||
Side effects happen inline as decisions crystallize:
|
||||
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `CONTEXT-FORMAT.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `references/context-format.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `ADR-FORMAT.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** Read `INTERFACE-DESIGN.md`.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `references/adr-format.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** Read `references/interface-design.md`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Deepening
|
||||
|
||||
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**.
|
||||
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**.
|
||||
|
||||
## Dependency categories
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
|
||||
|
||||
Uses the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
|
||||
Uses the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -11,7 +11,7 @@ Uses the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**,
|
||||
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
|
||||
|
||||
- The constraints any new interface would need to satisfy
|
||||
- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md))
|
||||
- The dependencies it would rely on, and which category they fall into (see [deepening.md](deepening.md))
|
||||
- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete
|
||||
|
||||
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
|
||||
@@ -20,21 +20,21 @@ Show this to the user, then immediately proceed to Step 2. The user reads and th
|
||||
|
||||
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
|
||||
|
||||
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
||||
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [deepening.md](deepening.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
||||
|
||||
- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point."
|
||||
- Agent 2: "Maximise flexibility — support many use cases and extension."
|
||||
- Agent 3: "Optimise for the most common caller — make the default case trivial."
|
||||
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
|
||||
|
||||
Include both [LANGUAGE.md](LANGUAGE.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
||||
Include both [language.md](language.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
||||
|
||||
Each sub-agent outputs:
|
||||
|
||||
1. Interface (types, methods, params — plus invariants, ordering, error modes)
|
||||
2. Usage example showing how callers use it
|
||||
3. What the implementation hides behind the seam
|
||||
4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md))
|
||||
4. Dependency strategy and adapters (see [deepening.md](deepening.md))
|
||||
5. Trade-offs — where leverage is high, where it's thin
|
||||
|
||||
### 3. Present and compare
|
||||
@@ -25,8 +25,8 @@ Describe the feature or bug. Expect the skill to ask what the public interface s
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Philosophy, the horizontal-slicing anti-pattern, the four-stage workflow, and the per-cycle checklist |
|
||||
| `tests.md` | Skill-root document, cited from Philosophy: worked good and bad test examples |
|
||||
| `mocking.md` | Skill-root document, cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `deep-modules.md` | Skill-root document, cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `interface-design.md` | Skill-root document, cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `refactoring.md` | Skill-root document, cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
| `references/tests.md` | Cited from Philosophy: worked good and bad test examples |
|
||||
| `references/mocking.md` | Cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `references/deep-modules.md` | Cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `references/interface-design.md` | Cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `references/refactoring.md` | Cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
|
||||
@@ -18,7 +18,7 @@ metadata:
|
||||
|
||||
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
||||
|
||||
If you need worked examples of the difference — a behaviour-level test beside the implementation-coupled version of the same check — read `tests.md`. If a test needs a collaborator faked, read `mocking.md` before reaching for a mock.
|
||||
If you need worked examples of the difference — a behaviour-level test beside the implementation-coupled version of the same check — read `references/tests.md`. If a test needs a collaborator faked, read `references/mocking.md` before reaching for a mock.
|
||||
|
||||
## Anti-Pattern: Horizontal Slices
|
||||
|
||||
@@ -55,8 +55,8 @@ Before writing any code:
|
||||
|
||||
- [ ] Confirm with user what interface changes are needed
|
||||
- [ ] Confirm with user which behaviors to test (prioritize)
|
||||
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](interface-design.md)
|
||||
- [ ] Identify opportunities for [deep modules](references/deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](references/interface-design.md)
|
||||
- [ ] List the behaviors to test (not implementation steps)
|
||||
- [ ] Get user approval on the plan
|
||||
|
||||
@@ -93,7 +93,7 @@ Rules:
|
||||
|
||||
### 4. Refactor
|
||||
|
||||
After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
After all tests pass, look for [refactor candidates](references/refactoring.md):
|
||||
|
||||
- [ ] Extract duplication
|
||||
- [ ] Deepen modules (move complexity behind simple interfaces)
|
||||
|
||||
@@ -31,5 +31,5 @@ Then describe what you want in natural language — "show me anything that needs
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The roles and state machine, the three invocation modes, the needs-info template, and how to resume a prior session |
|
||||
| `AGENT-BRIEF.md` | Skill-root document, cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `OUT-OF-SCOPE.md` | Skill-root document, cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
| `references/agent-brief.md` | Cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `references/out-of-scope.md` | Cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
|
||||
@@ -20,8 +20,8 @@ Every comment or issue posted to the issue tracker during triage **must** start
|
||||
|
||||
## Reference docs
|
||||
|
||||
- [AGENT-BRIEF.md](AGENT-BRIEF.md) — how to write durable agent briefs
|
||||
- [OUT-OF-SCOPE.md](OUT-OF-SCOPE.md) — how the `.out-of-scope/` knowledge base works
|
||||
- [agent-brief.md](references/agent-brief.md) — how to write durable agent briefs
|
||||
- [out-of-scope.md](references/out-of-scope.md) — how the `.out-of-scope/` knowledge base works
|
||||
|
||||
## Roles
|
||||
|
||||
@@ -74,11 +74,11 @@ Show counts and a one-line summary per issue. Let the maintainer pick.
|
||||
4. **Grill (if needed).** If the issue needs fleshing out, run a `/grill-with-docs` session.
|
||||
|
||||
5. **Apply the outcome:**
|
||||
- `ready-for-agent` — post an agent brief comment ([AGENT-BRIEF.md](AGENT-BRIEF.md)).
|
||||
- `ready-for-agent` — post an agent brief comment ([agent-brief.md](references/agent-brief.md)).
|
||||
- `ready-for-human` — same structure as an agent brief, but note why it can't be delegated (judgment calls, external access, design decisions, manual testing).
|
||||
- `needs-info` — post triage notes (template below).
|
||||
- `wontfix` (bug) — polite explanation, then close.
|
||||
- `wontfix` (enhancement) — write to `.out-of-scope/`, link to it from a comment, then close ([OUT-OF-SCOPE.md](OUT-OF-SCOPE.md)).
|
||||
- `wontfix` (enhancement) — write to `.out-of-scope/`, link to it from a comment, then close ([out-of-scope.md](references/out-of-scope.md)).
|
||||
- `needs-triage` — apply the role. Optional comment if there's partial progress.
|
||||
|
||||
## Quick state override
|
||||
|
||||
@@ -33,5 +33,5 @@ Describe the plan or design. Expect questions one at a time, each with a recomme
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The interview instruction plus the domain-awareness rules: file layout discovery, the five during-session behaviours, and the three-part ADR test |
|
||||
| `CONTEXT-FORMAT.md` | Skill-root document, cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `ADR-FORMAT.md` | Skill-root document, cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
| `references/context-format.md` | Cited when a term is resolved: the structure of a `CONTEXT.md` and how to write a Language entry |
|
||||
| `references/adr-format.md` | Cited when an ADR is offered: `docs/adr/` naming, sequential numbering, and the ADR template |
|
||||
|
||||
@@ -76,7 +76,7 @@ When the user states how something works, check whether the code agrees. If you
|
||||
|
||||
### Update CONTEXT.md inline
|
||||
|
||||
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).
|
||||
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [context-format.md](references/context-format.md).
|
||||
|
||||
Don't couple `CONTEXT.md` to implementation details. Only include terms that are meaningful to domain experts.
|
||||
|
||||
@@ -88,6 +88,6 @@ Only offer to create an ADR when all three are true:
|
||||
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
|
||||
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
|
||||
|
||||
If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
|
||||
If any of the three is missing, skip the ADR. Use the format in [adr-format.md](references/adr-format.md).
|
||||
|
||||
</supporting-info>
|
||||
|
||||
@@ -10,7 +10,7 @@ Looks for places where a codebase is hard to understand, hard to test, or hard f
|
||||
2. **Present candidates.** A numbered list, each with files, problem, solution and benefits — benefits stated in terms of *locality* and *leverage* and of how tests would improve. No interfaces are proposed yet; the user picks one.
|
||||
3. **Grilling loop.** Walks the design tree for the chosen candidate, with documentation side effects landing inline as decisions crystallise.
|
||||
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `LANGUAGE.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
The skill is opinionated about vocabulary, and that is the point: **module, interface, implementation, depth, seam, adapter, leverage, locality**, used exactly, with no drift into "component", "service", "API" or "boundary". Domain nouns come from `CONTEXT.md`, architecture nouns from `references/language.md` — so a proposal reads as "the Order intake module", never "the FooBarHandler".
|
||||
|
||||
ADRs are treated as decisions not to be re-litigated. A candidate that contradicts one is surfaced only when the friction is real enough to warrant reopening it, and is marked as such.
|
||||
|
||||
@@ -31,6 +31,6 @@ Point at a codebase or an area of one. Expect a numbered candidate list and a "w
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Condensed glossary, key principles, and the three-stage process |
|
||||
| `LANGUAGE.md` | Skill-root document, cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `INTERFACE-DESIGN.md` | Skill-root document, read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `DEEPENING.md` | Skill-root document, cited from `INTERFACE-DESIGN.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
| `references/language.md` | Cited throughout `SKILL.md`: full definitions of every term, the words each one replaces, and the full principle list |
|
||||
| `references/interface-design.md` | Read at stage 3 when the user wants alternative interfaces explored: the parallel sub-agent "Design It Twice" pattern, framing the problem space, and the per-agent design constraints |
|
||||
| `references/deepening.md` | Cited from `references/interface-design.md`: how to deepen a cluster of shallow modules safely, the four dependency categories (in-process, local-substitutable, remote-but-owned, true external), seam discipline, and the replace-don't-layer testing strategy |
|
||||
|
||||
@@ -33,7 +33,7 @@ Key principles:
|
||||
- **The interface is the test surface.**
|
||||
- **One adapter = hypothetical seam. Two adapters = real seam.**
|
||||
|
||||
If a term or principle above is ambiguous in the case in front of you, or you need the definitions and the principles the two lists leave out, read `LANGUAGE.md`.
|
||||
If a term or principle above is ambiguous in the case in front of you, or you need the definitions and the principles the two lists leave out, read `references/language.md`.
|
||||
|
||||
This skill is _informed_ by the project's domain model. The domain language gives names to good seams; ADRs record decisions the skill should not re-litigate.
|
||||
|
||||
@@ -74,7 +74,7 @@ Once the user picks a candidate, drop into a grilling conversation. Walk the des
|
||||
|
||||
Side effects happen inline as decisions crystallize:
|
||||
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `CONTEXT-FORMAT.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Naming a deepened module after a concept not in `CONTEXT.md`?** Add the term to `CONTEXT.md` — same discipline as `grill-with-docs`, in the format `grill-with-docs`'s `references/context-format.md` defines. Create the file lazily if it doesn't exist.
|
||||
- **Sharpening a fuzzy term during the conversation?** Update `CONTEXT.md` right there.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `ADR-FORMAT.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** Read `INTERFACE-DESIGN.md`.
|
||||
- **User rejects the candidate with a load-bearing reason?** Offer an ADR, framed as: _"Want me to record this as an ADR so future architecture reviews don't re-suggest it?"_ Only offer when the reason would actually be needed by a future explorer to avoid re-suggesting the same thing — skip ephemeral reasons ("not worth it right now") and self-evident ones. See `grill-with-docs`'s `references/adr-format.md`.
|
||||
- **Want to explore alternative interfaces for the deepened module?** Read `references/interface-design.md`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Deepening
|
||||
|
||||
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**.
|
||||
How to deepen a cluster of shallow modules safely, given its dependencies. Assumes the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**.
|
||||
|
||||
## Dependency categories
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
When the user wants to explore alternative interfaces for a chosen deepening candidate, use this parallel sub-agent pattern. Based on "Design It Twice" (Ousterhout) — your first idea is unlikely to be the best.
|
||||
|
||||
Uses the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
|
||||
Uses the vocabulary in [language.md](language.md) — **module**, **interface**, **seam**, **adapter**, **leverage**.
|
||||
|
||||
## Process
|
||||
|
||||
@@ -11,7 +11,7 @@ Uses the vocabulary in [LANGUAGE.md](LANGUAGE.md) — **module**, **interface**,
|
||||
Before spawning sub-agents, write a user-facing explanation of the problem space for the chosen candidate:
|
||||
|
||||
- The constraints any new interface would need to satisfy
|
||||
- The dependencies it would rely on, and which category they fall into (see [DEEPENING.md](DEEPENING.md))
|
||||
- The dependencies it would rely on, and which category they fall into (see [deepening.md](deepening.md))
|
||||
- A rough illustrative code sketch to ground the constraints — not a proposal, just a way to make the constraints concrete
|
||||
|
||||
Show this to the user, then immediately proceed to Step 2. The user reads and thinks while the sub-agents work in parallel.
|
||||
@@ -20,21 +20,21 @@ Show this to the user, then immediately proceed to Step 2. The user reads and th
|
||||
|
||||
Spawn 3+ sub-agents in parallel using the Agent tool. Each must produce a **radically different** interface for the deepened module.
|
||||
|
||||
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [DEEPENING.md](DEEPENING.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
||||
Prompt each sub-agent with a separate technical brief (file paths, coupling details, dependency category from [deepening.md](deepening.md), what sits behind the seam). The brief is independent of the user-facing problem-space explanation in Step 1. Give each agent a different design constraint:
|
||||
|
||||
- Agent 1: "Minimize the interface — aim for 1–3 entry points max. Maximise leverage per entry point."
|
||||
- Agent 2: "Maximise flexibility — support many use cases and extension."
|
||||
- Agent 3: "Optimise for the most common caller — make the default case trivial."
|
||||
- Agent 4 (if applicable): "Design around ports & adapters for cross-seam dependencies."
|
||||
|
||||
Include both [LANGUAGE.md](LANGUAGE.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
||||
Include both [language.md](language.md) vocabulary and CONTEXT.md vocabulary in the brief so each sub-agent names things consistently with the architecture language and the project's domain language.
|
||||
|
||||
Each sub-agent outputs:
|
||||
|
||||
1. Interface (types, methods, params — plus invariants, ordering, error modes)
|
||||
2. Usage example showing how callers use it
|
||||
3. What the implementation hides behind the seam
|
||||
4. Dependency strategy and adapters (see [DEEPENING.md](DEEPENING.md))
|
||||
4. Dependency strategy and adapters (see [deepening.md](deepening.md))
|
||||
5. Trade-offs — where leverage is high, where it's thin
|
||||
|
||||
### 3. Present and compare
|
||||
@@ -25,8 +25,8 @@ Describe the feature or bug. Expect the skill to ask what the public interface s
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | Philosophy, the horizontal-slicing anti-pattern, the four-stage workflow, and the per-cycle checklist |
|
||||
| `tests.md` | Skill-root document, cited from Philosophy: worked good and bad test examples |
|
||||
| `mocking.md` | Skill-root document, cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `deep-modules.md` | Skill-root document, cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `interface-design.md` | Skill-root document, cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `refactoring.md` | Skill-root document, cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
| `references/tests.md` | Cited from Philosophy: worked good and bad test examples |
|
||||
| `references/mocking.md` | Cited from Philosophy: mock at system boundaries only, and what not to mock |
|
||||
| `references/deep-modules.md` | Cited from stage 1: what a deep module is (small interface, large implementation) and why it is the design to aim for |
|
||||
| `references/interface-design.md` | Cited from stage 1: designing interfaces for testability, starting with accepting dependencies rather than creating them |
|
||||
| `references/refactoring.md` | Cited from stage 4: the refactor-candidate checklist — duplication, long methods, shallow modules, feature envy, primitive obsession |
|
||||
|
||||
@@ -18,7 +18,7 @@ metadata:
|
||||
|
||||
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
||||
|
||||
If you need worked examples of the difference — a behaviour-level test beside the implementation-coupled version of the same check — read `tests.md`. If a test needs a collaborator faked, read `mocking.md` before reaching for a mock.
|
||||
If you need worked examples of the difference — a behaviour-level test beside the implementation-coupled version of the same check — read `references/tests.md`. If a test needs a collaborator faked, read `references/mocking.md` before reaching for a mock.
|
||||
|
||||
## Anti-Pattern: Horizontal Slices
|
||||
|
||||
@@ -55,8 +55,8 @@ Before writing any code:
|
||||
|
||||
- [ ] Confirm with user what interface changes are needed
|
||||
- [ ] Confirm with user which behaviors to test (prioritize)
|
||||
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](interface-design.md)
|
||||
- [ ] Identify opportunities for [deep modules](references/deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](references/interface-design.md)
|
||||
- [ ] List the behaviors to test (not implementation steps)
|
||||
- [ ] Get user approval on the plan
|
||||
|
||||
@@ -93,7 +93,7 @@ Rules:
|
||||
|
||||
### 4. Refactor
|
||||
|
||||
After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
After all tests pass, look for [refactor candidates](references/refactoring.md):
|
||||
|
||||
- [ ] Extract duplication
|
||||
- [ ] Deepen modules (move complexity behind simple interfaces)
|
||||
|
||||
@@ -31,5 +31,5 @@ Then describe what you want in natural language — "show me anything that needs
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `SKILL.md` | The roles and state machine, the three invocation modes, the needs-info template, and how to resume a prior session |
|
||||
| `AGENT-BRIEF.md` | Skill-root document, cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `OUT-OF-SCOPE.md` | Skill-root document, cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
| `references/agent-brief.md` | Cited when an issue moves to `ready-for-agent` (and reused for `ready-for-human`): how to write a brief that stays durable for weeks while the codebase moves under it — describe interfaces and behavioural contracts, not line numbers |
|
||||
| `references/out-of-scope.md` | Cited when an enhancement is closed `wontfix` and when checking for prior rejections: how the `.out-of-scope/` knowledge base is laid out and what it is for — institutional memory, and deduplication against re-litigated requests |
|
||||
|
||||
@@ -20,8 +20,8 @@ Every comment or issue posted to the issue tracker during triage **must** start
|
||||
|
||||
## Reference docs
|
||||
|
||||
- [AGENT-BRIEF.md](AGENT-BRIEF.md) — how to write durable agent briefs
|
||||
- [OUT-OF-SCOPE.md](OUT-OF-SCOPE.md) — how the `.out-of-scope/` knowledge base works
|
||||
- [agent-brief.md](references/agent-brief.md) — how to write durable agent briefs
|
||||
- [out-of-scope.md](references/out-of-scope.md) — how the `.out-of-scope/` knowledge base works
|
||||
|
||||
## Roles
|
||||
|
||||
@@ -74,11 +74,11 @@ Show counts and a one-line summary per issue. Let the maintainer pick.
|
||||
4. **Grill (if needed).** If the issue needs fleshing out, run a `/grill-with-docs` session.
|
||||
|
||||
5. **Apply the outcome:**
|
||||
- `ready-for-agent` — post an agent brief comment ([AGENT-BRIEF.md](AGENT-BRIEF.md)).
|
||||
- `ready-for-agent` — post an agent brief comment ([agent-brief.md](references/agent-brief.md)).
|
||||
- `ready-for-human` — same structure as an agent brief, but note why it can't be delegated (judgment calls, external access, design decisions, manual testing).
|
||||
- `needs-info` — post triage notes (template below).
|
||||
- `wontfix` (bug) — polite explanation, then close.
|
||||
- `wontfix` (enhancement) — write to `.out-of-scope/`, link to it from a comment, then close ([OUT-OF-SCOPE.md](OUT-OF-SCOPE.md)).
|
||||
- `wontfix` (enhancement) — write to `.out-of-scope/`, link to it from a comment, then close ([out-of-scope.md](references/out-of-scope.md)).
|
||||
- `needs-triage` — apply the role. Optional comment if there's partial progress.
|
||||
|
||||
## Quick state override
|
||||
|
||||
20
plugins/gitea/.env.example
Normal file
20
plugins/gitea/.env.example
Normal file
@@ -0,0 +1,20 @@
|
||||
# Environment variables required by the gitea MCP server declared in
|
||||
# plugins/gitea/.mcp.json. apm passes these ${VAR} references through to the
|
||||
# deployed MCP config unexpanded; Claude Code resolves them from the process
|
||||
# environment at server startup. Neither value is ever committed to this repo.
|
||||
#
|
||||
# Nothing in this repo auto-loads a .env file -- apm has no dotenv support.
|
||||
# Copy this file to .env at the repo root, fill in real values, then export it
|
||||
# into your shell before starting Claude Code, e.g.:
|
||||
#
|
||||
# set -a; source .env; set +a
|
||||
#
|
||||
# Or skip the file and export the two variables directly in your shell
|
||||
# profile. Either way, never commit .env -- .gitignore already excludes it.
|
||||
|
||||
# A Gitea access token, scoped to the repositories this agent should reach.
|
||||
# Generate one in Gitea under Settings > Applications.
|
||||
GITEA_ACCESS_TOKEN=<your-gitea-access-token>
|
||||
|
||||
# The base URL of your Gitea instance, including scheme.
|
||||
GITEA_HOST=https://<your-gitea-host>
|
||||
Reference in New Issue
Block a user