Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .agents/advanced-safety-rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# 🚨 Advanced safety rules

- Do **not** auto-update external dependencies without explicit request.
- Do **not** inject analytics or telemetry code.
- Flag any usage of unsafe constructs (e.g., reflection, I/O on the main thread).
- Avoid generating blocking calls inside coroutines.
14 changes: 14 additions & 0 deletions .agents/documentation-guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Documentation & comments

## Commenting guidelines
- Avoid inline comments in production code unless necessary.
- Inline comments are helpful in tests.
- When using TODO comments, follow the format on the [dedicated page][todo-comments].
- File and directory names should be formatted as code.

## Avoid widows, runts, orphans, or rivers

Agents should **AVOID** text flow patters illustrated
on [this diagram](widow-runt-orphan.jpg).

[todo-comments]: https://github.com/SpineEventEngine/documentation/wiki/TODO-comments
20 changes: 20 additions & 0 deletions .agents/documentation-tasks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# 📄 Documentation tasks

1. Ensure all public and internal APIs have KDoc examples.
2. Add in-line code blocks for clarity in tests.
3. Convert inline API comments in Java to KDoc in Kotlin:
```java
// Literal string to be inlined whenever a placeholder references a non-existent argument.
private final String missingArgumentMessage = "[MISSING ARGUMENT]";
```
transforms to:
```kotlin
/**
* Literal string to be inlined whenever a placeholder references a non-existent argument.
*/
private val missingArgumentMessage = "[MISSING ARGUMENT]"
```

4. Javadoc -> KDoc conversion tasks:
- Remove `<p>` tags in the line with text: `"<p>This"` -> `"This"`.
- Replace `<p>` with empty line if the tag is the only text in the line.
17 changes: 17 additions & 0 deletions .agents/memory/MEMORY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Team memory index

One line per memory. Scan at the start of every session.
See [README.md](README.md) for the format and routing rules.

## Feedback (validated patterns & corrections)

- [copilot-review-request](feedback/copilot-review-request.md) — GraphQL `requestReviews` with `botIds: ["BOT_kgDOCnlnWA"]`; REST endpoint silently no-ops on re-requests.

## Project (durable context & rationale)

*(no entries yet)*

## Reference (external systems)

- [cache-warm-window](reference/cache-warm-window.md) — How prompt cache entries are shared between sibling-repo sessions and how to maximise overlap.
- [anthropic-api-caching](reference/anthropic-api-caching.md) — Pattern and pricing for adding prompt caching to any direct Anthropic API call.
89 changes: 89 additions & 0 deletions .agents/memory/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Team memory — `.agents/memory/`

Validated patterns, durable project context, and pointers to external
systems. Checked into git so the whole team — and any agent working in
this repo — benefits from accumulated knowledge.

This complements Claude Code's built-in per-developer auto-memory:
team-shareable knowledge lives here; personal preferences and ephemeral
state live in the auto-memory.

## Layout

.agents/memory/
├── MEMORY.md # Index — scan at start of every session
├── README.md # This file — read when adding/updating memories
├── feedback/ # Validated patterns & corrections
├── project/ # Durable project context & rationale
└── reference/ # External systems & resources

One file per memory. Filename = the memory's kebab-case slug.

## File format

---
name: tests-no-db-mocks
description: One-line summary — used to surface relevance, so be specific.
metadata:
type: feedback # feedback | project | reference
since: 2026-05-19 # date added (ISO)
---

<one-paragraph rule or fact>

**Why:** <reason — incident, constraint, team convention>

**How to apply:** <when this kicks in; what to do or avoid>

Related: [[other-memory-slug]]

`Why:` and `How to apply:` are required for `feedback` and `project`
memories — they let future readers judge edge cases. `reference`
memories may be shorter (link + one-line purpose).

Link related memories with `[[slug]]` (the target file's `name:`).

## Routing — repo vs. auto-memory

| Kind of fact | Goes to |
|---|---|
| Personal preference, role, style | auto-memory (`user`) |
| Personal habit feedback | auto-memory (`feedback`) |
| Team coding/test/PR rule | **`feedback/`** |
| Durable project rationale | **`project/`** |
| Ephemeral project state (freezes, OOO, deadlines) | auto-memory (`project`) — would rot in git |
| Team-shared external resource | **`reference/`** |
| Personal external resource | auto-memory (`reference`) |

**Litmus test:** *would a teammate joining the project next month benefit
from knowing this?* If no, it belongs in auto-memory.

## Write protocol

1. Write the file **uncommitted** in the working tree.
2. **Surface the change** in the same turn so the human can review.
3. **Do not auto-commit** memory edits as part of an unrelated PR — memory
changes should be reviewable on their own.
4. **Correct in place** when an existing memory turns out wrong; `git blame`
carries the history.
5. **Propose deletion explicitly** when a memory has gone stale, rather
than silently editing it out.

## Updating the index

After adding or removing a memory file, update `MEMORY.md`. One line under
the matching section:

- [slug](category/slug.md) — description from frontmatter

Keep the index short — long descriptions belong in the file body.

## Anti-patterns — do not store

- Anything derivable from the code (module structure, paths, conventions
visible in source). Use `grep` / `Read`.
- Recent-activity summaries or PR lists — `git log` is authoritative.
- Fix recipes for specific bugs — the commit message belongs in the commit.
- Anything already documented in `.agents/` reference docs — keep one
source of truth.
- Personal preferences (see routing).
Empty file.
35 changes: 35 additions & 0 deletions .agents/memory/feedback/copilot-review-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
name: copilot-review-request
description: How to request or re-request a Copilot PR review programmatically — GraphQL botIds is the only reliable path
metadata:
type: feedback
since: 2026-05-25
---

Use the GraphQL `requestReviews` mutation with `botIds` for both initial
requests and re-requests:

```bash
gh api graphql -f query='
mutation {
requestReviews(input: {
pullRequestId: "PR_NODE_ID",
botIds: ["BOT_kgDOCnlnWA"]
}) {
pullRequest { id number }
}
}'
```

- `PR_NODE_ID`: `gh api repos/SpineEventEngine/REPO/pulls/NUMBER --jq '.node_id'`
- `BOT_kgDOCnlnWA`: fixed node ID for the Copilot PR reviewer bot (stable)

**Why:** The REST endpoint (`POST .../requested_reviewers` with
`reviewers[]=Copilot`) silently no-ops on re-requests — it only works for
the first-ever request on a PR. The GraphQL `userIds` field also fails
because Copilot is a Bot, not a User. `botIds` is the correct field and
works for both initial and re-requests.

**How to apply:** Any time a Copilot review needs to be requested or
re-requested, use the GraphQL mutation above. Do not use the REST endpoint
or `@copilot review` comments.
Empty file added .agents/memory/project/.gitkeep
Empty file.
Empty file.
52 changes: 52 additions & 0 deletions .agents/memory/reference/anthropic-api-caching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
name: anthropic-api-caching
description: Pattern and pricing for adding prompt caching to any direct Anthropic API call.
metadata:
type: reference
since: 2026-05-24
---

Use this when adding a direct Anthropic API call (GitHub Actions workflow,
script, or tool) that sends a stable system prompt.

**Add `cache_control` to the system message block:**

```python
system=[{
"type": "text",
"text": "<stable system prompt — skill definition, shared instructions, etc.>",
"cache_control": {"type": "ephemeral", "ttl": "1h"}
}]
```

Use `ttl: "1h"` for any caller whose requests are spaced more than 5 minutes
apart (GitHub Actions jobs, scheduled tasks, skill invocations). Use the
default 5-minute TTL only for tight interactive loops.

**Pricing (input tokens):**

| Operation | Cost multiplier |
|---|---|
| Cache write (5-min TTL) | 1.25× base input price |
| Cache write (1-hour TTL) | 2× base input price |
| Cache read (any TTL) | 0.1× base input price |

A single cache hit within the TTL window recovers the write premium. Multiple
hits within the hour make the 2× write cost negligible.

**Place stable content before dynamic content.** Cache breakpoints apply to
everything *before* the `cache_control` marker. Dynamic per-request content
(user query, file diff, current date) must come after the last breakpoint.

**Monitor hits via the usage object:**
```python
print(response.usage.cache_read_input_tokens) # 0 on miss, >0 on hit
print(response.usage.cache_creation_input_tokens) # tokens written to cache
```

**Future:** once direct API calls exist in this org, consider a cache pre-warm
job triggered on push to `master` — calls the API with `max_tokens: 0` and
`cache_control: {ttl: "1h"}` so the first session after a config change
hits rather than writes.

Related: [[cache-warm-window]]
33 changes: 33 additions & 0 deletions .agents/memory/reference/cache-warm-window.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: cache-warm-window
description: How prompt cache entries are shared between sibling-repo sessions and how to maximise overlap.
metadata:
type: reference
since: 2026-05-24
---

Claude Code sessions share a prompt cache entry when they send byte-identical
content within the cache TTL window. Because `migrate` copies `CLAUDE.md` and
`.agents/` verbatim, any two sessions on the same config version share the
same cache slot — provided they fall within the TTL.

**TTL in effect for Console OAuth users:**
- Default: **5 minutes** (applies to all non-subscription auth)
- With `ENABLE_PROMPT_CACHING_1H=1` in `~/.claude/settings.json`: **1 hour**

Developers must have `ENABLE_PROMPT_CACHING_1H=1` set, otherwise the
window is too short for cross-session hits to occur reliably.
This setting will work ONLY for Claude Code which runs the CLI binary.
It will not work for JetBrains Air or any other IDE plugin which does not
run the Claude Code CLI binary.

**Cache is per Anthropic workspace.** All developers authenticated via the
same Anthropic organisation Console org share the same cache pool. Do not
create separate Console workspaces per developer — that would isolate their
cache entries.

**Practical impact:** Realistic concurrency is 1–2 sessions at a time. The
first session after a config change pays the cache-write cost; any session
starting within the next hour (with 1H TTL) reads from cache at 0.1× cost.

Related: [[anthropic-api-caching]]
59 changes: 59 additions & 0 deletions .agents/project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Project: documentation

## Overview

This repository is the **documentation aggregator and content host** for the
Spine SDK. It owns the Hugo site setup that gathers documentation from sibling
SDK repos (currently `SpineEventEngine/validation`) as Hugo modules, and it
also stores original Markdown content under `docs/`. The repo additionally
serves as the GitHub Wiki source for committer-facing documentation about
contributing to the framework.

The public site at [spine.io](https://spine.io) is built from
`SpineEventEngine/SpineEventEngine.github.io`, which **imports this repo's
`docs/` directory as a Hugo module**. Edits made here flow to the public site
when `SpineEventEngine.github.io` bumps its module pin.

## Architecture

**Role in the org:** documentation aggregator + content host.

**Stack.** A Hugo + Node project at heart. Gradle is a thin task-runner
wrapper around Hugo, Node, and Go tooling — not a JVM build in any meaningful
sense, so JVM coding conventions do not apply here.

- `docs/` — published content, Hugo site root, exported as a Hugo module to
`SpineEventEngine.github.io`.
- `docs/_preview/` — local-only Hugo setup for running the site during
authoring (`./gradlew :runSite`, or `hugo server` from this directory).
- `docs/_code/examples/*` — git submodules pinned at
`spine-examples/{airport, blog, hello, kanban, todo-list}`. These are the
**canonical source of embedded code samples**; this repo does not modify
them.
- `config/` — git submodule pointing at `SpineEventEngine/config`. Provides
shared agent guidance, skills, and build config consumed across Spine SDK
repos. Applied via the `Apply config` step.
- Theme: components, layouts, and styles come from the `site-commons` Hugo
theme (`github.com/SpineEventEngine/site-commons`).

**Doc modules pulled in via `docs/hugo.toml`.** Currently only the
`validation` repo contributes docs as a Hugo module. The README lists
`framework` and `compiler` as examples of how to add more; they are not
wired in today.

**Key conventions and constraints (not obvious from the code):**

- **Theme changes mirror to spine.io.** Any non-trivial change to
`site-commons` usage here must also be applied in the main `spine.io` site
repo, or the live site will diverge from preview.
- **Embedded code must round-trip.** Code blocks in pages are generated from
the `docs/_code` submodules by the [`embed-code`][embed-code] tool. Do not
hand-edit embedded code blocks in Markdown; run `./gradlew :embedCode` and
verify with `./gradlew :checkSamples`. See [`EMBEDDING.md`](../EMBEDDING.md).
- **Submodules are pinned.** `docs/_code/examples/*` and `config` are pinned
intentionally — do not bump them as a side effect of unrelated work.
- **Link checking is required pre-PR.** Run the `check-links` skill before
opening any PR that touches `docs/**` or `site/**`; CI runs the same check
via `lychee.toml` against the rendered HTML.

[embed-code]: https://github.com/SpineEventEngine/embed-code-go
18 changes: 18 additions & 0 deletions .agents/project.template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!-- Template — copy to a sibling repo's .agents/project.md and fill in the
sections below. In the config repo itself this file is a template only. -->

# Project: <name>

## Overview

*One paragraph: what this repo is, what problem it solves, and its role in the
Spine SDK organisation.*

## Architecture

*Role in the org: library / tool / Gradle plugin / application.
Key patterns, public API boundaries, and constraints specific to this repo.*

<!-- JVM projects: uncomment the line below after seeding this file.
Read [`.agents/jvm-project.md`](jvm-project.md) for build stack, coding style, tests, and versioning.
-->
Loading
Loading