This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 635830881dcb16559a6bd0dac1966e75eb123dc9
Author: Stephen Mallette <[email protected]>
AuthorDate: Sun Aug 9 08:26:01 2026 -0400

    Add the tinker-dev and tinker-doc Agent Skills to 3.7-dev
    
    Backports the skills and bin/agent-setup.sh from master, retargeted to
    this branch: top-level gremlin-javascript and gremlint rather than a
    gremlin-js workspace, no gremlin-mcp, neo4j-gremlin and sparql-gremlin
    in the validation rules, and Java 8/11 in place of 17. The skill now
    also states the non-breaking constraint that governs a 3.7.x change.
    
    Assisted-by: Claude Code:claude-opus-5
---
 .skills/tinker-dev/DESIGN.md                       |  38 +++
 .skills/tinker-dev/SKILL.md                        | 164 ++++++++++
 .../tinker-dev/references/dev-environment-setup.md | 123 +++++++
 .skills/tinker-dev/scripts/check-env.sh            | 160 +++++++++
 .skills/tinker-doc/DESIGN.md                       |  33 ++
 .skills/tinker-doc/SKILL.md                        | 141 ++++++++
 .../tinker-doc/references/asciidoc-and-wiring.md   | 175 ++++++++++
 .skills/tinker-doc/references/books-and-voice.md   | 363 +++++++++++++++++++++
 .skills/tinker-doc/references/executable-blocks.md |  91 ++++++
 bin/agent-setup.sh                                 | 341 +++++++++++++++++++
 10 files changed, 1629 insertions(+)

diff --git a/.skills/tinker-dev/DESIGN.md b/.skills/tinker-dev/DESIGN.md
new file mode 100644
index 0000000000..4ad70ab7e3
--- /dev/null
+++ b/.skills/tinker-dev/DESIGN.md
@@ -0,0 +1,38 @@
+# tinker-dev — Design
+
+How this skill is structured and how to change it. The development guidance
+itself — build recipes, the validation matrix, conventions, beads rules — is 
the
+skill's *content* and lives in `SKILL.md` and `references/`. This document is 
only
+the shape of the artifact and where new content goes.
+
+## Structure
+
+A guidance skill, not a program:
+
+| Path | Role |
+|------|------|
+| `SKILL.md` | the operational index — the guidance a reader needs up front |
+| `references/*.md` | deep, task-specific material, loaded on demand |
+| `scripts/check-env.sh` | environment preflight |
+
+It carries no logic of its own; its effect is what a reader does after reading 
it.
+
+## How to change it — where content goes
+
+Two rules govern the shape, so every change is a routing decision:
+
+- **Single source of truth — defer, don't duplicate.** General agent rules live
+  in the root `AGENTS.md`; canonical facts live in the repo (`CONTRIBUTING.md`,
+  `docs/src/`, `bin/asf-license-header.txt`). New guidance points at its source
+  and repeats only the TinkerPop-specific thing that is easy to miss. A fact
+  copied here drifts from its source — so it isn't.
+- **Progressive disclosure.** `SKILL.md` stays a lean index; anything deep or
+  task-specific becomes a `references/` file linked from it, never inlined.
+
+Applying them:
+
+- A **general** agent rule → root `AGENTS.md`, not here.
+- A **TinkerPop-specific, easy-to-miss** convention → a bullet in `SKILL.md`,
+  deferring to the canonical file.
+- A **new validation rule** → the Definition-of-Done matrix in `SKILL.md`.
+- A **new deep topic** → a `references/` file, linked from `SKILL.md`.
diff --git a/.skills/tinker-dev/SKILL.md b/.skills/tinker-dev/SKILL.md
new file mode 100644
index 0000000000..df4db69999
--- /dev/null
+++ b/.skills/tinker-dev/SKILL.md
@@ -0,0 +1,164 @@
+---
+name: tinker-dev
+description: >
+  Development guidance for the Apache TinkerPop monorepo. Use when building,
+  testing, or contributing to TinkerPop's graph computing framework and its
+  multi-language Gremlin ecosystem (Java, Python, JavaScript, .NET, Go).
+  Covers coding conventions, build recipes, test evaluation, documentation,
+  and development environment setup.
+license: Apache-2.0
+compatibility: Requires Java 8 or 11 (build with 11, cross-compiled to 8), 
Maven 3.5.3+, Docker. Individual GLVs may need Python, Node.js, .NET SDK, or Go.
+metadata:
+  version: 1.0.0
+  project: Apache TinkerPop
+---
+
+# TinkerPop Development Skill
+
+## Project Overview
+
+Apache TinkerPop is a graph computing framework providing a standard API (the 
Gremlin graph
+traversal language) for graph databases and processors. The repository is a 
Maven multi-module
+monorepo that wraps JVM code, Python, JavaScript/TypeScript, .NET, and Go 
under a single build.
+
+Canonical project documentation (prefer local files over external URLs):
+
+- `README.md` and `CONTRIBUTING.md` at the repo root
+- Reference docs: `docs/src/reference/`
+- Developer docs: `docs/src/dev/developer/`
+- Provider docs and Gremlin Semantics: `docs/src/dev/provider/`
+- IO and Serialization: `docs/src/dev/io/`
+- Recipes: `docs/src/recipes/`
+- Upgrade docs: `docs/src/upgrade/`
+- Future plans: `docs/src/dev/future/`
+
+## Definition of Done
+
+A change is **not done** until a full Maven validation has passed locally. Run 
it before
+presenting work for review — even when your targeted or unit tests already 
pass, and even if you
+judge a full run unnecessary. Incremental testing during development is 
encouraged, but it does
+**not** satisfy this gate.
+
+Validation is two steps. First, rebuild and install the whole reactor so every 
module picks up
+your changes:
+
+```bash
+mvn clean install -DskipTests
+```
+
+Then run `verify` scoped to what you changed, using the **broadest** rule that 
applies, and
+always list every module you touched.
+
+**Self-contained modules** — changing one of these only requires validating 
that module:
+
+| Changed module | Validate command |
+|---|---|
+| Python GLV | `mvn verify -pl gremlin-python` |
+| JavaScript GLV | `mvn verify -pl :gremlin-javascript` |
+| .NET GLV | `mvn verify -pl 
:gremlin-dotnet,:gremlin-dotnet-source,:gremlin-dotnet-tests` |
+| Go GLV | `mvn verify -pl :gremlin-go` |
+| `gremlint` | `mvn verify -pl :gremlint` |
+| Other single JVM module (e.g. `tinkergraph-gremlin`, `gremlin-console`, 
`neo4j-gremlin`, `sparql-gremlin`, `gremlin-archetype`) | `mvn verify -pl 
<module> -DskipIntegrationTests=false` |
+
+**Shared modules** — depended on by others, so changing them means validating 
the consumers too.
+Use the broadest rule that matches:
+
+- **`gremlin-server`, `gremlin-driver`, or `gremlin-util`** define the wire 
protocol and
+  serialization that every GLV exercises → validate the changed module(s) 
**plus all GLVs**:
+  `mvn verify -pl 
<changed>,gremlin-python,:gremlin-javascript,:gremlin-dotnet,:gremlin-dotnet-source,:gremlin-dotnet-tests,:gremlin-go
 -DskipIntegrationTests=false`
+- **`gremlin-core`, `gremlin-test`, or anything they depend on** ripple across 
the whole project,
+  including the OLAP engines (`hadoop-gremlin`, `spark-gremlin`) and the graph 
implementations
+  (`neo4j-gremlin`, `sparql-gremlin`) → run everything:
+  `mvn clean install -DskipIntegrationTests=false`
+- **Unsure?** Treat it as the `gremlin-core` case and run everything.
+
+**Docs or code comments only** — no validation gate; this gate is for changes 
that affect behavior.
+
+### Things that quietly invalidate a run
+
+- **GLV tests are skipped unless activated.** A GLV is built and tested only 
when its `.glv`
+  sentinel exists: `gremlin-python/.glv`, `gremlin-go/.glv`, and *both* 
`gremlin-dotnet/src/.glv`
+  and `gremlin-dotnet/test/.glv` (JavaScript builds by default). Without the 
sentinel the module
+  is silently skipped — a green run may have tested nothing of your change. 
Create the sentinel
+  (or pass `-Pglv-python` / `-Pglv-go`) before validating a GLV change.
+- **Grammar and feature-test changes need a reactor build to take effect.** 
The ANTLR grammar
+  (`gremlin-language/src/main/antlr4/Gremlin.g4`) and the Gherkin features 
under `gremlin-test`
+  drive code generation during `mvn clean install` — ANTLR parsers, and 
per-language test code
+  generated from the feature corpus (e.g. 
`gremlin-python/build/generate.groovy`, with
+  equivalents for Go, .NET, and JavaScript). After changing either, run `mvn 
clean install
+  -DskipTests` before relying on *any* test, including fast native ones, or 
you will be testing
+  stale generated code.
+- **Judge pass/fail by the Maven exit code, not console text.** Do not 
`grep`/`tail` the build
+  output — tests deliberately emit expected errors, so the log misleads. Exit 
`0` = pass. For
+  Python, detailed per-suite results are in 
`gremlin-python/target/python3/python-reports/*.xml`.
+
+If you cannot run the validation (for example, Docker is unavailable), say so 
explicitly and
+report the change as **not validated** — do not present it as done.
+
+## Repository Structure
+
+Most module names map directly to their purpose (`gremlin-core`, 
`gremlin-server`,
+`gremlin-go`, etc.). Two things that aren't obvious:
+
+- **Every module is top-level**, including the JavaScript ones: 
`gremlin-javascript/` (the
+  `gremlin` npm driver) and `gremlint/` sit directly under the repository 
root. Later branches
+  group them under a `gremlin-js/` workspace, so a path from `master` will not 
resolve here.
+- **Maven orchestrates the build for every module, including the non-JVM 
ones** (Python,
+  JavaScript, .NET, Go) — which is why the validation in the Definition of 
Done runs through
+  Maven rather than each language's native test runner.
+
+This branch also carries `neo4j-gremlin` and `sparql-gremlin` (graph 
implementations) and
+`gremlin-archetype` (Maven archetypes for new projects), none of which exist 
on `master`.
+
+Cross-language Gherkin feature tests live in `gremlin-test/`.
+
+## Basic Build Commands
+
+Build everything:
+```bash
+mvn clean install
+```
+
+Build a specific module:
+```bash
+mvn clean install -pl <module-name>
+```
+
+For GLV-specific builds and the validation commands per module, see the 
**Definition of Done**
+table above. For environment setup and GLV activation, see 
`references/dev-environment-setup.md`.
+
+## Conventions
+
+The general Do/Don't rules and "when in doubt" guidance live in the root 
`AGENTS.md` — the
+single source of truth, not repeated here. The conventions below are the 
TinkerPop-specific
+ones that are easy to miss:
+
+- **This is a maintenance branch.** `3.7-dev` takes non-breaking bug fixes and 
enhancements
+  only. Within the 3.7.x line a change must not alter existing behavior, 
introduce new APIs,
+  change serialization formats, or modify protocols — a client of one 3.7.x 
version must still
+  interact correctly with a server of another. Anything that fails that test 
belongs on a later
+  branch. See `docs/src/dev/developer/for-committers.asciidoc`.
+- **License header**: every new file needs the ASF header. Canonical text: 
`bin/asf-license-header.txt`.
+- **Test naming**: a test using a `GraphProvider` with `AbstractGremlinTest` 
is suffixed
+  `Check`, not `Test`.
+- **Gremlin language tests**: cross-language behavior is tested with Gherkin 
features under
+  `gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/`
+  (see `docs/src/dev/developer/for-committers.asciidoc`).
+- **Docs are AsciiDoc** under `docs/src/` — never Markdown in the main docs 
tree. For writing or
+  revising any documentation (voice, per-book style, executable code blocks, 
AsciiDoc wiring),
+  use the **tinker-doc** skill. The mechanical minimum: add new content to the 
right book and update
+  its `index.asciidoc`.
+- **Changelog**: for user-visible or API changes, add a concise 
`CHANGELOG.asciidoc` entry in the
+  correct version section. Do not invent version numbers or release names. See 
the **tinker-doc**
+  skill for changelog discipline (one entry per user-facing change, not per 
commit) and voice.
+
+Otherwise, match the existing code in neighboring files — explicit imports (no 
wildcards),
+`final` where practical, SLF4J logging over `println`, Hamcrest matchers, and 
closing any
+`Graph` you construct in a test.
+
+## Reference Guides
+
+Build and validate commands live in the **Definition of Done** table above. 
For the remaining
+task-specific guidance, see:
+
+- [Development Environment Setup](references/dev-environment-setup.md) — fresh 
clone to working environment, prerequisites, GLV activation
diff --git a/.skills/tinker-dev/references/dev-environment-setup.md 
b/.skills/tinker-dev/references/dev-environment-setup.md
new file mode 100644
index 0000000000..f94935b6b5
--- /dev/null
+++ b/.skills/tinker-dev/references/dev-environment-setup.md
@@ -0,0 +1,123 @@
+# Development Environment Setup
+
+This guide walks through setting up a TinkerPop development environment from a 
fresh clone.
+The canonical reference is 
`docs/src/dev/developer/development-environment.asciidoc`.
+
+## Prerequisites
+
+### Minimum (Java-only build)
+
+- **Java 8 or 11** — OpenJDK recommended, with Java 11 preferred: the build 
cross-compiles to
+  Java 8 bytecode. Use [SDKMAN!](https://sdkman.io/) to manage versions. Java 
17 also compiles,
+  but deep reflection needs the `--add-opens` JVM options already configured 
in the pom files.
+  Use Java 11 for documentation generation with `bin/process-docs.sh`.
+- **Maven 3.5.3+** — also manageable via SDKMAN.
+
+With just Java and Maven you can build JVM modules and get a clean `mvn clean 
install`, but
+GLV builds and many integration tests will be skipped.
+
+### Full environment (all GLVs and integration tests)
+
+- **Docker and Docker Compose** — required for all GLV test execution. Docker 
Desktop includes
+  both. GLV tests run inside Docker containers, so local language runtimes are 
optional for
+  test execution via Maven.
+- **Python 3.9–3.13** — optional for local development; Docker handles test 
execution.
+- **Node.js 20+ / npm 10+** — optional; Maven downloads a local copy via 
`frontend-maven-plugin`
+  (`node.version` and `npm.version` in the root `pom.xml` pin the exact 
versions used by the
+  build). Consider [nvm](https://github.com/nvm-sh/nvm) for version management.
+- **.NET SDK 6.0+** — optional; Docker handles test execution. `Gremlin.Net` 
targets
+  `netstandard2.0` and `net6.0`.
+- **Go 1.25+** — optional; Docker handles test execution.
+
+## Environment Verification
+
+Run the included check script to verify your setup:
+
+```bash
+bash .skills/tinker-dev/scripts/check-env.sh
+```
+
+This checks for Java, Maven, Docker, and optionally Python, Node.js, .NET, and 
Go.
+
+## First Build
+
+After cloning, verify the basic build works:
+
+```bash
+mvn clean install -DskipTests
+```
+
+This builds all JVM modules. GLV modules will be skipped unless activated (see 
below).
+
+## Activating GLV Builds
+
+Each Gremlin Language Variant uses a `.glv` sentinel file to signal Maven that 
the GLV
+should be built as part of a standard `mvn clean install`. The file can be 
empty.
+
+### Python
+```bash
+touch gremlin-python/.glv
+```
+
+### JavaScript / TypeScript
+No `.glv` file needed — JS modules build by default via the 
`frontend-maven-plugin`.
+Tests require Docker and are skipped with `-DskipTests`.
+
+### .NET
+Both `src` and `test` directories need the sentinel:
+```bash
+touch gremlin-dotnet/src/.glv
+touch gremlin-dotnet/test/.glv
+```
+
+### Go
+```bash
+touch gremlin-go/.glv
+```
+
+Once `.glv` files are in place, a standard `mvn clean install` will include 
those GLVs.
+The `.glv` files are gitignored.
+
+Alternatively, activate GLV builds explicitly with Maven profiles without 
`.glv` files:
+- Python: `mvn clean install -Pglv-python -pl :gremlin-python`
+- .NET: `mvn clean install -Pgremlin-dotnet -pl 
:gremlin-dotnet,:gremlin-dotnet-source,:gremlin-dotnet-tests`
+- Go: `mvn clean install -Pglv-go -pl :gremlin-go`
+
+## Groovy / Ivy Configuration
+
+The Gremlin Console is Groovy-based. For documentation generation or console 
testing with
+SNAPSHOT dependencies, configure `~/.groovy/grapeConfig.xml`:
+
+```xml
+<ivysettings>
+  <settings defaultResolver="downloadGrapes"/>
+  <resolvers>
+    <chain name="downloadGrapes">
+      <ibiblio name="local" root="file:${user.home}/.m2/repository/" 
m2compatible="true"/>
+      <ibiblio name="central" root="https://repo1.maven.org/maven2/"; 
m2compatible="true"/>
+    </chain>
+  </resolvers>
+</ivysettings>
+```
+
+## Docker Permissions (Linux)
+
+If you encounter "Permission denied" errors:
+
+```bash
+sudo groupadd docker
+sudo usermod -aG docker $USER
+newgrp docker
+sudo chmod 666 /var/run/docker.sock
+```
+
+## IDE Setup
+
+TinkerPop does not mandate a specific IDE. Import the root `pom.xml` as a 
Maven project.
+For AI coding agent configuration, see the "Using AI Coding Agents" section in
+`docs/src/dev/developer/development-environment.asciidoc`.
+
+## Next Steps
+
+- See the **Definition of Done** table in `SKILL.md` for the build and 
validate commands per
+  module / GLV.
diff --git a/.skills/tinker-dev/scripts/check-env.sh 
b/.skills/tinker-dev/scripts/check-env.sh
new file mode 100755
index 0000000000..1be8ac2fe0
--- /dev/null
+++ b/.skills/tinker-dev/scripts/check-env.sh
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Verify TinkerPop development environment prerequisites.
+# Usage: bash .skills/tinker-dev/scripts/check-env.sh
+
+set -uo pipefail
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+NC='\033[0m'
+
+pass=0
+warn=0
+fail=0
+
+ok()   { echo -e "  ${GREEN}✓${NC} $1"; pass=$((pass + 1)); }
+skip() { echo -e "  ${YELLOW}○${NC} $1"; warn=$((warn + 1)); }
+bad()  { echo -e "  ${RED}✗${NC} $1"; fail=$((fail + 1)); }
+
+echo "TinkerPop Development Environment Check"
+echo "========================================"
+echo ""
+
+# --- Java ---
+echo "Core prerequisites:"
+if command -v java &>/dev/null; then
+    # Java 8 reports itself as "1.8.0_xxx", everything since as "11.0.2" or 
"17".
+    java_version=$(java -version 2>&1 | head -1 | sed 's/.*"\(.*\)".*/\1/')
+    case "$java_version" in
+        1.*) java_version=$(echo "$java_version" | cut -d. -f2) ;;
+        *)   java_version=$(echo "$java_version" | cut -d. -f1) ;;
+    esac
+    if [[ "$java_version" -eq 11 ]]; then
+        ok "Java $java_version (preferred for 3.7-dev)"
+    elif [[ "$java_version" -eq 8 ]]; then
+        ok "Java $java_version (supported; Java 11 is preferred and required 
for bin/process-docs.sh)"
+    elif [[ "$java_version" -gt 11 ]]; then
+        skip "Java $java_version found — 3.7-dev targets Java 8 and builds 
best on 11 (use sdkman.io to switch)"
+    else
+        bad "Java $java_version found — version 8 or 11 required (use 
sdkman.io to install)"
+    fi
+else
+    bad "Java not found — install Java 8 or 11 (use sdkman.io)"
+fi
+
+# --- Maven ---
+if command -v mvn &>/dev/null; then
+    mvn_version=$(mvn --version 2>/dev/null | head -1 | grep -oE 
'[0-9]+\.[0-9]+\.[0-9]+' | head -1)
+    ok "Maven $mvn_version (3.5.3+ required)"
+else
+    bad "Maven not found — install Maven 3.5.3+ (try sdkman.io)"
+fi
+
+# --- Docker ---
+if command -v docker &>/dev/null; then
+    if docker info &>/dev/null; then
+        ok "Docker installed and running"
+    else
+        bad "Docker installed but not running — start Docker Desktop or the 
daemon"
+    fi
+else
+    bad "Docker not found — install Docker Desktop (includes Compose)"
+fi
+
+# --- Docker Compose ---
+if docker compose version &>/dev/null 2>&1; then
+    ok "Docker Compose available"
+elif command -v docker-compose &>/dev/null; then
+    ok "Docker Compose (standalone) available"
+else
+    skip "Docker Compose not found — needed for GLV tests"
+fi
+
+echo ""
+echo "Optional (GLV development):"
+
+# --- Python ---
+if command -v python3 &>/dev/null; then
+    py_version=$(python3 --version 2>&1 | grep -oE '[0-9]+\.[0-9]+')
+    ok "Python $py_version (3.9-3.13 supported for gremlin-python local dev)"
+else
+    skip "Python 3 not found — Docker handles test execution, but local dev 
needs it"
+fi
+
+# --- Node.js ---
+if command -v node &>/dev/null; then
+    node_version=$(node --version 2>/dev/null | sed 's/v//')
+    ok "Node.js $node_version (20+ recommended for gremlin-javascript local 
dev)"
+else
+    skip "Node.js not found — Maven downloads a local copy automatically"
+fi
+
+# --- .NET SDK ---
+if command -v dotnet &>/dev/null; then
+    dotnet_version=$(dotnet --version 2>/dev/null)
+    ok ".NET SDK $dotnet_version (6.0+ recommended for gremlin-dotnet local 
dev)"
+else
+    skip ".NET SDK not found — Docker handles test execution"
+fi
+
+# --- Go ---
+if command -v go &>/dev/null; then
+    go_version=$(go version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?')
+    ok "Go $go_version (1.25+ recommended for gremlin-go local dev)"
+else
+    skip "Go not found — Docker handles test execution"
+fi
+
+echo ""
+echo "GLV activation status:"
+
+# --- .glv sentinel files ---
+check_glv() {
+    local name="$1"
+    shift
+    local found=false
+    for f in "$@"; do
+        if [[ -f "$f" ]]; then
+            found=true
+        fi
+    done
+    if $found; then
+        ok "$name — activated (.glv present)"
+    else
+        skip "$name — not activated (create .glv to enable in standard builds)"
+    fi
+}
+
+check_glv "gremlin-python" "gremlin-python/.glv"
+check_glv "gremlin-dotnet" "gremlin-dotnet/src/.glv" "gremlin-dotnet/test/.glv"
+check_glv "gremlin-go" "gremlin-go/.glv"
+
+echo ""
+echo "----------------------------------------"
+echo -e "Results: ${GREEN}$pass passed${NC}, ${YELLOW}$warn skipped${NC}, 
${RED}$fail failed${NC}"
+
+if [[ $fail -gt 0 ]]; then
+    echo ""
+    echo "Fix the failed items above before building. See 
references/dev-environment-setup.md"
+    exit 1
+fi
diff --git a/.skills/tinker-doc/DESIGN.md b/.skills/tinker-doc/DESIGN.md
new file mode 100644
index 0000000000..b7fd2d679c
--- /dev/null
+++ b/.skills/tinker-doc/DESIGN.md
@@ -0,0 +1,33 @@
+# tinker-doc — Design
+
+How this skill is structured and how to change it. The documentation guidance
+itself — per-book voice, house style, the executable-block rules — is the 
skill's
+*content* and lives in `SKILL.md` and `references/`. This document is only the
+shape of the artifact and where new content goes.
+
+## Structure
+
+A guidance skill, not a program:
+
+| Path | Role |
+|------|------|
+| `SKILL.md` | the book map, house style, and the load-bearing rules up front |
+| `references/*.md` | the voice guide and authoring mechanics, loaded on 
demand |
+
+## How to change it — where content goes
+
+Two rules govern the shape, so every change is a routing decision:
+
+- **Single source of truth — defer, don't duplicate.** Guidance that overlaps
+  development (build/validation, changelog discipline) defers to **tinker-dev**
+  rather than being restated. Canonical documentation lives under `docs/src/`.
+- **Progressive disclosure.** `SKILL.md` holds the rule; the details live in a
+  `references/` file linked from it.
+
+Applying them:
+
+- A **new book or audience** → a row in the book map in `SKILL.md`, plus a 
voice
+  entry in `references/books-and-voice.md`.
+- A **new authoring mechanic** → `references/executable-blocks.md` or
+  `references/asciidoc-and-wiring.md`; keep `SKILL.md` to the rule, not the 
how.
+- A **new house-style rule** → the House style list in `SKILL.md`.
diff --git a/.skills/tinker-doc/SKILL.md b/.skills/tinker-doc/SKILL.md
new file mode 100644
index 0000000000..d09f918d8a
--- /dev/null
+++ b/.skills/tinker-doc/SKILL.md
@@ -0,0 +1,141 @@
+---
+name: tinker-doc
+description: >
+  Writing, editing and reviewing documentation for the Apache TinkerPop 
project. Use 
+  when  authoring or revising any content under docs/src/ — reference docs, 
recipes,
+  tutorials, upgrade/release notes, provider and developer guides — or the
+  CHANGELOG. Covers the TinkerPop documentation voice and the per-book style
+  expectations, the executable Gremlin code-block pipeline, and AsciiDoc
+  conventions. For building and validating code changes, see tinker-dev.
+license: Apache-2.0
+compatibility: Documentation is AsciiDoc under docs/src/, never Markdown.
+metadata:
+  version: 1.0.0
+  project: Apache TinkerPop
+---
+
+# TinkerPop Documentation Skill
+
+This skill is about the **craft** of TinkerPop documentation: getting the 
voice,
+audience, and shape of each kind of document right. The mechanics that keep the
+build green (executable code blocks, AsciiDoc wiring) are covered in the
+references and matter, but they serve the writing, not the other way around.
+
+All project documentation lives under `docs/src/` and is **AsciiDoc, never
+Markdown**. It is organized into several books, each with its own audience and
+purpose. The four directories under `docs/src/dev/` are themselves separate
+books, not one:
+
+| Book | Path | Audience | Purpose |
+|---|---|---|---|
+| Reference | `docs/src/reference/` | Users | The complete, authoritative 
description of every feature and step |
+| Recipes | `docs/src/recipes/` | Users | Reusable problem→solution patterns 
for real tasks |
+| Tutorials | `docs/src/tutorials/` | Users (learning) | Story-driven 
walkthroughs of a focused topic |
+| Upgrade | `docs/src/upgrade/` | Users (upgrading) | Announces what changed 
in a release and how to adapt |
+| Provider | `docs/src/dev/provider/` | Graph providers | Implementation 
guidance, provider policies, and the canonical Gremlin semantics |
+| IO | `docs/src/dev/io/` | Providers and advanced users | The serialization 
formats (GraphBinary, GraphSON, GraphML, Gryo) |
+| Developer | `docs/src/dev/developer/` | Contributors | Contributing, 
development environment, committer and release process |
+| Future | `docs/src/dev/future/` | Contributors | Design proposals for 
planned or possible changes |
+
+The full per-book voice guide, with grounded examples from the real docs, is in
+[references/books-and-voice.md](references/books-and-voice.md). Read it before
+writing in any book you have not written in before. The short version of each
+book's character:
+
+- **Upgrade** announces. It tells a feature's story — what changed and why it
+  matters — and defers exhaustive detail to the reference docs via `See:` 
rather
+  than cataloging every edge case itself. A typical entry is short: a 
paragraph or
+  two and one example. It frames past shortcomings positively and treats 
breaking
+  changes as a priority.
+- **Reference and Recipes** instruct. They are the focal point for correct
+  usage and established patterns: complete, user-friendly, and formal.
+- **Tutorials** teach through a story but otherwise follow the 
Reference/Recipes
+  style.
+- **Provider** documents internals in the Reference/Recipes style. The
+  `gremlin-semantics.asciidoc` file is special and load-bearing (see below).
+- **IO** specifies the serialization formats in the same formal, complete style
+  as Provider.
+- **Developer** docs are internal notes, instructions and standard processes 
for contributors.
+- **Future** holds design proposals for changes under consideration.
+
+## House style (applies to every book)
+
+These rules hold across all documentation. Existing prose does not always obey
+them; write to the standard, not to the weakest nearby example.
+
+1. **No em-dash or semicolon to break a sentence.** Prefer two separate
+   sentences, or find a transition word that lets the thought flow. (This is a
+   prose rule. Semicolons inside code, such as the `;[]` output-suppression
+   idiom, are unaffected.)
+2. **Formal means no first or second person.** Do not address the reader as
+   "you" or speak as "I" or "we." Write about the subject, not about the author
+   or audience. "The `coalesce()`-step evaluates..." not "You can use
+   `coalesce()` to...".
+3. **Prefer flowing paragraphs over lists.** Use a bulleted or numbered list
+   only when it itemizes something clearly quantifiable, such as the members of
+   an enumeration or a fixed set of options, each needing description. Do not 
use
+   a list for open-ended or subjective points (for example, "the benefits of a
+   traversal pattern"). Those belong in prose.
+4. **Avoid hype and marketing language.** Describe what something does and why 
it
+   matters in plain, positive terms. Let the capability speak for itself.
+
+## Examples must be real and runnable
+
+TinkerPop documentation is unusual: most Gremlin examples are **executed at 
build
+time** against a real graph, and their output is inlined automatically. A block
+marked `[gremlin-groovy,modern]` is run against the modern toy graph and its
+output is filled in for you. Never invent or hand-write the `==>` output of 
such
+a block.
+
+The two graphs available to executable blocks are `modern` and `existing`. Use
+a bare `[gremlin-groovy]` block for setup that should run without a graph. When
+an example is purely illustrative and must *not* be executed (a hypothetical, 
an
+error case, console session text), use `[source,text]` or `[source,groovy]`
+instead.
+
+**Exception — upgrade documentation is always static.** Every example in
+`docs/src/upgrade/` is a hand-written `[source,groovy]` or `[source,text]` 
block,
+**never** an executable `[gremlin-groovy]` block, because an upgrade entry is a
+snapshot of behavior at a fixed point in history (often an old-vs-new
+comparison). This reverses the general rule above: in upgrade docs you **do**
+write the `==>` output by hand. "Static" does not mean "no output" — a static
+upgrade example should still show its results so the reader sees the payoff. 
If an
+upgrade example is missing its output, the fix is to write the output in, 
**not**
+to convert the block to executable. Do not be talked out of this by the rest of
+the docs being executable, and do not assume the upgrade book contains 
executable
+blocks — it does not.
+
+The authoring details — graph choice, output suppression, `<1>` callouts, and
+the multi-language story — are in
+[references/executable-blocks.md](references/executable-blocks.md). AsciiDoc
+structure (anchors, cross-references, section-title length limits for the TOC,
+the `x.y.z` version placeholder, per-book `index.asciidoc` wiring, admonitions,
+images) is in
+[references/asciidoc-and-wiring.md](references/asciidoc-and-wiring.md).
+
+## The semantics document is load-bearing
+
+`docs/src/dev/provider/gremlin-semantics.asciidoc` is the canonical description
+of Gremlin's semantics. **It must be updated whenever Gremlin steps, the 
Gremlin
+grammar (`Gremlin.g4`), or the semantics code change in any way.** When adding 
to
+it, follow the patterns already established there for how a concept or step is
+documented rather than inventing a new structure. See
+[references/books-and-voice.md](references/books-and-voice.md#provider-documentation)
+for what those patterns are.
+
+## Don't forget the changelog and upgrade docs
+
+Behavioral and API changes usually need more than reference updates:
+
+- **`CHANGELOG.asciidoc`** (repo root) gets a concise entry in the correct
+  version section. One short clause, written for what the user will see on
+  release day — the net user-facing change, from a usage perspective — not the
+  implementation detail. Do not invent version numbers or release names.
+  - The changelog is not a commit log. Not every commit earns an entry, and a
+    feature built over many commits should have **one** entry, not one per
+    increment. When extending an unreleased feature, fold the change into its
+    existing entry rather than appending a new line; if a change has no
+    user-visible effect, it needs no entry at all.
+- **Upgrade docs** get an entry for user-visible features and especially for
+  breaking changes to public APIs or Gremlin semantics. A breaking change
+  without clear migration guidance in the upgrade docs is incomplete.
diff --git a/.skills/tinker-doc/references/asciidoc-and-wiring.md 
b/.skills/tinker-doc/references/asciidoc-and-wiring.md
new file mode 100644
index 0000000000..ae904cf37b
--- /dev/null
+++ b/.skills/tinker-doc/references/asciidoc-and-wiring.md
@@ -0,0 +1,175 @@
+# AsciiDoc and Wiring
+
+TinkerPop documentation is AsciiDoc, never Markdown. This reference covers the
+structural conventions an agent gets wrong most often. For voice see
+`books-and-voice.md`; for runnable examples see `executable-blocks.md`.
+
+## Anchors and cross-references
+
+Define an anchor on its own line above the heading it names, then link to it 
from
+anywhere with `<<anchor,display text>>`:
+
+```
+[[coalesce-step]]
+=== Coalesce Step
+
+... see the <<where-step,where()-step>> for a related filter.
+```
+
+Give every section a stable, descriptive anchor and prefer cross-referencing an
+existing section over restating its content.
+
+**`<<anchor>>` only resolves inside its own book.** Each book under `docs/src/`
+builds as a separate document, so a cross-reference from one book to another 
does
+not work even when the anchor exists. It also fails *silently* rather than
+breaking the build: `<<subgraph-step>>` renders as the literal text
+`[subgraph-step]`, and `<<gremlin-java-pdt,Gremlin-Java>>` renders as a dead
+same-page link to a fragment the page does not contain.
+
+To point at another book, use a full `link:` to the published site instead:
+
+```
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#labels-step[labels()]
+```
+
+This matters most in the upgrade book, which is nearly always talking about
+reference, provider, or IO material that lives elsewhere. Note that upgrade 
docs
+pin a concrete version rather than `x.y.z` — see the exception below.
+
+## Section titles must fit the TOC
+
+Section titles that publish to the table of contents (the `====` level and 
above)
+must not exceed 30 characters, or they wrap in the fixed-width TOC when 
published.
+
+## The `x.y.z` version placeholder
+
+Links into version-specific resources use the literal placeholder `x.y.z` in
+place of a release number. The build substitutes the real version. This applies
+to javadoc links, links into the published site, and GitHub source links:
+
+```
+link:https://tinkerpop.apache.org/docs/x.y.z/reference/#gremlin-console[Gremlin
 Console]
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/.../GraphTraversal.html#coalesce(...)++[`coalesce(Traversal...)`]
+```
+
+Never hard-code a concrete version like `3.7.6` in these links. The `++...++`
+double-plus wrapping is used to escape URLs that contain characters AsciiDoc 
would
+otherwise interpret (such as the parentheses in a javadoc method signature).
+
+**Exception: upgrade documentation.** Links from the upgrade docs to other
+versioned documentation are deliberately pinned to a concrete version (for
+example `.../docs/3.7.4/reference/...`), not `x.y.z` and not `current`, 
because an
+upgrade entry is a snapshot in time. This exception applies *only* to the 
upgrade
+book. See
+[books-and-voice.md](books-and-voice.md#upgrade-documentation) for the full
+reasoning.
+
+If you need actually use `x.y.z` as a literal value, prefer `xx.yy.zz`.
+
+## Additional References blocks
+
+Reference step sections end with a pointer block under a bold label. It always
+carries the javadoc link, and when the step has an entry in the Gremlin 
Semantics
+documentation it also links there with the link text `` `Semantics` ``:
+
+```
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/core/.../GraphTraversal.html#conjoin(java.lang.String)++[`conjoin(String)`]
+link:++https://tinkerpop.apache.org/docs/x.y.z/dev/provider/#conjoin-step++[`Semantics`]
+```
+
+The semantics link points to `dev/provider/#<step>-step` (the anchor in
+`gremlin-semantics.asciidoc`), uses the `x.y.z` placeholder, and is wrapped in
+`++...++`. Whenever a step's behavior is specified in the semantics document,
+include this link so the reference and the specification stay connected. Match
+this format when adding a new step so the reference stays uniform.
+
+## See blocks (upgrade documentation)
+
+Upgrade documentation has its own closing convention. An upgrade entry ends 
with a
+`See:` line that points the reader to the sources where the change can be 
explored
+in more depth. Where reference sections use `*Additional References*`, upgrade
+entries use `See:`.
+
+A single pointer:
+
+```
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-3225[TINKERPOP-3225]
+```
+
+Several pointers are comma-separated, each `link:` on its own line, all under 
one
+`See:`:
+
+```
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2672[TINKERPOP-2672],
+link:https://tinkerpop.apache.org/docs/3.7.1/reference/#asString-step[asString()-step],
+link:https://tinkerpop.apache.org/docs/3.7.1/reference/#length-step[length()-step]
+```
+
+Conventions observed in the upgrade docs:
+
+- **JIRA issues** are the most common target. The link text is the bare ticket
+  id, `TINKERPOP-XXXX`, linking to 
`https://issues.apache.org/jira/browse/TINKERPOP-XXXX`.
+- **Reference (and other doc) links** are version-pinned, not `x.y.z` (see the
+  upgrade exception above), with descriptive link text such as
+  `Reference Documentation - Metrics` or the step name `trim()-step`.
+- **Mailing-list threads** point to `https://lists.apache.org/thread/...` with
+  link text naming the thread, often beginning `[DISCUSS]`.
+- **Proposals** link to the proposal file on GitHub, for example
+  
`https://github.com/apache/tinkerpop/blob/master/docs/src/dev/future/proposal-scoping-5.asciidoc`,
+  with a descriptive title as the link text.
+
+Use `See:` with the colon. A scattering of older entries omit it; the colon is 
the
+standard.
+
+## Book wiring: `index.asciidoc`
+
+Each book has an `index.asciidoc` that sets document attributes and pulls in 
its
+content files with `include::` directives, in reading order:
+
+```
+:docinfo: shared
+:toc-position: left
+
+include::the-graph.asciidoc[]
+include::the-traversal.asciidoc[]
+```
+
+A **new content file is invisible until it is included.** After creating a 
file,
+add an `include::` for it to that book's `index.asciidoc` at the correct 
position.
+Forgetting this is the most common reason new documentation does not appear.
+
+## Admonitions
+
+AsciiDoc admonitions call out information without breaking into a list. The 
four
+in regular use, in rough order of frequency, are `NOTE:`, `IMPORTANT:`, 
`WARNING:`,
+and `TIP:`. Use them for genuine asides and cautions, not as a substitute for
+well-structured prose:
+
+```
+IMPORTANT: This tutorial assumes the Gremlin Console is installed.
+```
+
+## Images
+
+Images are referenced with `image::file.png[width=500]` for block images and
+`image:file.png[width=130]` (single colon) for inline ones. Image files live
+under `docs/static/images/`. Set a sensible `width`, and `align="center"` where
+the surrounding content does.
+
+## Quick checklist for a new or changed doc
+
+The list below is a fixed, enumerable set of mechanical steps, which is exactly
+the case where a list is appropriate:
+
+1. Right book, right file, AsciiDoc not Markdown.
+2. Stable `[[anchor]]` on every new section.
+3. Executable examples use `[gremlin-groovy,modern]` (or `existing`); no
+   hand-written `==>` output. Non-executed examples use `[source,text]`.
+4. Version-specific links use the `x.y.z` placeholder.
+5. New files added to the book's `index.asciidoc` via `include::`.
+6. Semantics, grammar, or step changes reflected in
+   `gremlin-semantics.asciidoc`.
+7. User-visible or breaking changes reflected in `CHANGELOG.asciidoc` and the
+   upgrade docs.
diff --git a/.skills/tinker-doc/references/books-and-voice.md 
b/.skills/tinker-doc/references/books-and-voice.md
new file mode 100644
index 0000000000..3548c0994b
--- /dev/null
+++ b/.skills/tinker-doc/references/books-and-voice.md
@@ -0,0 +1,363 @@
+# Books and Voice
+
+Each book in `docs/src/` serves a different reader at a different moment. 
Getting
+a document right starts with knowing which book it belongs to and writing in 
that
+book's voice. The house-style rules in `SKILL.md` (no em-dash or 
sentence-breaking
+semicolon, formal third person, paragraphs over lists, no hype) apply 
throughout.
+The guidance below is what is specific to each book.
+
+---
+
+## Upgrade Documentation
+
+`docs/src/upgrade/` — one file per minor line (`release-3.7.x.asciidoc`, etc.),
+newest release section at the top, split into "Upgrading for Users" and, where
+relevant, provider-facing notes.
+
+Upgrade documentation **announces** a release. It is the place where a feature 
is
+introduced to the world. This shapes everything about how it reads.
+
+**It is not a coding reference; it tells a story.** An upgrade entry gives the
+reader a clear, engaging account of what a feature is and why it matters, then
+lets them follow the `See:` references for the full detail when they want it. 
The
+goal is to make the feature interesting and understood, not to specify it. 
State
+the point of the change and show one good example, then stop.
+
+**Do not catalog every corner of the feature.** This is the most common way an
+upgrade entry goes wrong. Resist enumerating every overload, every argument
+variation, and every runtime behavior (what happens with zero, with a partial
+result, when nothing remains, and so on). That exhaustive cataloging is 
precisely
+what the reference and semantics docs are for, and the `See:` link sends the
+reader there. A well-chosen example already demonstrates the important 
behaviors,
+so a prose paragraph that narrates each case after it is usually redundant and
+should be cut.
+
+A typical upgrade entry is short: a heading, a paragraph or two on what changed
+and why it matters, one example, and the `See:` line. The clearest warning 
sign is
+a paragraph after the example that walks through edge cases such as an empty
+result, a zero argument, or an exhausted iterator. That reads as specification
+rather than story, and it is what the reference docs behind the `See:` link are
+for. The test for any sentence is whether it conveys why the feature is useful 
or
+merely specifies how it behaves. The latter belongs in the reference docs.
+
+**Announce without hype.** The tone is positive and informative, never
+marketing. Avoid "powerful," "blazing fast," "game-changing," and similar.
+Describe the capability plainly and let it be interesting on its own terms.
+
+**Frame past shortcomings positively.** When a release fixes a bug or removes a
+limitation, describe it as an improvement to how TinkerPop works now, not as a
+confession of how broken it used to be. State what the old behavior was 
factually,
+then what the new behavior is, without self-criticism.
+
+**Lead major changes with history.** When a release changes how TinkerPop does
+something fundamental, breaks with tradition, or alters a public API, open the
+section with a short account of how the project arrived here. That context is 
what
+makes a disruptive change feel reasoned rather than arbitrary. This history is
+often more nuanced than the changeset reveals, so do not try to reconstruct it 
by
+searching the internet or inferring it from the diff. If the history is not
+already at hand, ask the human for it.
+
+**Compare old and new syntax in examples.** The most useful upgrade example 
shows
+the before and the after side by side. The established pattern uses comment
+labels inside a single block:
+
+```
+[source,groovy]
+----
+// 3.7.6
+gremlin> g.inject([null]).conjoin("-")
+==>null
+
+// 3.7.7
+gremlin> g.inject([null]).conjoin("+")
+==>
+----
+```
+
+**Upgrade examples must always be static blocks.** Use `[source,groovy]` or
+`[source,text]`, never an executable `[gremlin-groovy]` block. An upgrade 
example
+is a snapshot of behavior at a specific moment in the project's history, often
+contrasting two versions at once. It must not be regenerated against the 
current
+build, which would erase the very before-and-after the example exists to show.
+
+Static does not mean output-free. A static upgrade example should still include
+its results, written in by hand, so the reader sees the payoff of the change:
+
+```
+[source,groovy]
+----
+gremlin> g.V().has('age', gt(__.V(1).values('age'))).values('name')
+==>josh
+==>peter
+----
+```
+
+When reviewing upgrade docs, a query example shown without its expected results
+is a real gap, but the fix is to **add the hand-written `==>` output**, never 
to
+convert the block to executable. Converting it would defeat the snapshot 
purpose
+and is always the wrong call in this book.
+
+**Examples should be impactful, not exhaustive or contrived.** Choose a use 
case
+that catches attention and makes the value obvious. One well-chosen, realistic
+example beats five that exercise every option.
+
+**Breaking changes are the priority.** Breaking changes to public APIs and to
+Gremlin semantics are the most important thing upgrade documentation does. For
+each one, state clearly what breaks, why, and exactly how a user minimizes the
+impact (what to change in their code, what to check for). A breaking change
+documented without a migration path is incomplete.
+
+**Close an entry with a `See:` block.** Most upgrade entries end with a `See:`
+line that sends the reader to where the change can be explored further: the 
JIRA
+issue, the relevant reference documentation, a `[DISCUSS]` mailing-list 
thread, a
+design proposal, or several of these together. The JIRA issue is the most 
common
+and uses the bare ticket id as its link text (`See:
+link:...[TINKERPOP-XXXX]`). The full format, including how multiple targets are
+listed, is in
+[asciidoc-and-wiring.md](asciidoc-and-wiring.md#see-blocks-upgrade-documentation).
+
+**Pin cross-reference links to a concrete version.** This is the one place 
where
+the usual `x.y.z` placeholder rule does *not* apply. Because an upgrade entry 
is a
+snapshot tied to a specific release, a link out to the reference docs (or any
+other versioned documentation) must name the actual version it refers to, not
+`x.y.z` and not `current`:
+
+```
+See: link:https://tinkerpop.apache.org/docs/3.7.4/reference/#metrics[Reference 
Documentation - Metrics]
+```
+
+A `current` or `x.y.z` link would drift as new releases ship and eventually 
point
+the reader at documentation that no longer matches the change being described.
+This pinning is peculiar to upgrade documentation. Everywhere else, use the
+`x.y.z` placeholder as normal.
+
+---
+
+## Reference Documentation
+
+`docs/src/reference/` — the authoritative, complete description of TinkerPop.
+`the-traversal.asciidoc` documents the steps; other files cover variants,
+applications, and implementations.
+
+Reference documentation **instructs**. Where upgrade docs introduced a feature,
+reference docs are the focal point for its proper, ongoing use. The style is
+**user-friendly, complete, informative, and formal**.
+
+The established shape of a step section:
+
+```
+[[coalesce-step]]
+=== Coalesce Step
+
+The `coalesce()`-step evaluates the provided traversals in order and returns 
the
+first traversal that emits at least one element.
+
+[gremlin-groovy,modern]
+----
+g.V(1).coalesce(outE('knows'), 
outE('created')).inV().path().by('name').by(label)
+----
+
+*Additional References*
+
+link:++https://tinkerpop.apache.org/javadocs/x.y.z/.../GraphTraversal.html#coalesce(...)++[`coalesce(Traversal...)`]
+```
+
+Conventions to follow:
+
+- A dedicated anchor (`[[coalesce-step]]`) and a `=== Title Case Step` heading.
+- An opening sentence that defines the step in third person, naming it as
+  `` `coalesce()`-step `` and, where the docs do so for its neighbors, tagging
+  its category in bold (for example `*filter*` or `*map*`).
+- One or more **executable** `[gremlin-groovy,modern]` examples that 
demonstrate
+  real behavior on the toy graph.
+- An `*Additional References*` block linking to the javadoc, and, when the step
+  has an entry in the Gremlin Semantics documentation, a `` `Semantics` `` 
link to
+  `dev/provider/#<step>-step`. Both use the `x.y.z` version placeholder (see
+  `asciidoc-and-wiring.md`).
+
+Completeness matters here in a way it does not in the upgrade docs. The 
reference
+is where a user goes to learn how a step actually behaves in all its normal 
uses.
+
+---
+
+## Recipes Documentation
+
+`docs/src/recipes/` — one file per pattern.
+
+Recipes share Reference's voice (user-friendly, complete, informative, formal)
+but are organized around a **task** rather than a feature. A recipe states a
+problem a user genuinely has, then builds the traversal that solves it,
+explaining the reasoning as it goes.
+
+The signature recipe device is the **numbered callout**, which attaches prose
+explanation to specific lines without breaking the flow of the example:
+
+```
+[gremlin-groovy,modern]
+----
+g.V(1).bothE()                                   <1>
+g.V(1).bothE().where(otherV().hasId(2))          <2>
+----
+
+<1> There are three edges from the vertex with the identifier of "1".
+<2> Filter those three edges using the `where()`-step ...
+```
+
+Recipes often layer from a simple case to progressively richer ones, which 
suits
+the "build up a solution" framing. Keep the prose between examples flowing and
+formal.
+
+---
+
+## Tutorials
+
+`docs/src/tutorials/` — `getting-started`, `the-gremlin-console`,
+`gremlins-anatomy`, `gremlin-language-variants`, each in its own directory.
+
+Tutorials are **story-driven** and cover one focused topic, taking a reader 
from
+unfamiliar to capable. Beyond that narrative arc, they follow the
+Reference/Recipes style: complete, informative, and formal. Tutorials make 
heavy
+use of `link:` cross-references out to the published site (with the `x.y.z`
+placeholder) to connect the story to the reference material, and they open with
+`:docinfo: shared` directives and a logo image.
+
+Note that some existing tutorial prose slips into second person ("inspire you 
to
+new levels"). That is legacy phrasing, not the standard. New and revised 
tutorial
+content should stay in formal third person like the rest of the documentation.
+
+---
+
+## Provider Documentation
+
+`docs/src/dev/provider/` — for graph providers implementing TinkerPop, and to
+some extent for advanced users. The voice matches Reference and Recipes:
+informative, complete, formal.
+
+### The semantics document
+
+`gremlin-semantics.asciidoc` is the canonical specification of how Gremlin
+behaves: equality, comparability, orderability, equivalence, type promotion, 
and
+the semantics of each construct. **It must be updated whenever Gremlin steps, 
the
+grammar (`Gremlin.g4`), or the semantics code change in any way.** Treat it as
+part of the change, not an afterthought.
+
+The semantics document is language-agnostic: it specifies Gremlin behavior for
+every GLV. Do not name Java-specific types, exception classes, syntax, or 
library
+functions in normative prose. The reference implementation is linked from each
+step's `See:` block, and that is the appropriate place for any Java-flavored
+specifics. For exceptions, name the TinkerPop error category rather than a Java
+exception class. The categories are defined by the Errors table near the top of
+the document, which is the authority on which ones exist — do not use a 
category
+that is not a row in that table.
+
+For types, use the `GType` enum names (`STRING`, `INT`, `LONG`, `BIGINT`,
+`BIGDECIMAL`, `FLOAT`, `DOUBLE`, `BOOLEAN`, `UUID`, `DATETIME`, `DURATION`,
+`BINARY`, `CHAR`, `NULL`, `NUMBER`, `LIST`, `SET`, `MAP`, plus graph types), 
not
+the Java class names that back them. This applies to collections and generics 
as
+much as to scalars: write `SET<STRING>`, `LIST<STRING>`, `MAP<STRING, any>`, 
and
+`Traversal<any, STRING>` — never `Set<String>`, `Collection<String>`, or
+`Traversal<?, ?>`. Use `any` for an unconstrained type parameter.
+
+Note that `GType` has no `Collection` supertype, so there is nothing to 
translate
+`Collection<String>` directly into. `LIST` and `SET` are distinct types and
+neither subsumes the other, so a step accepting either takes "a `LIST` or 
`SET` of
+`STRING`". Check the step's source rather than assuming, since narrowing the
+contract to one of them is a real error.
+
+Java-specific naming also leaks in through configuration and enum names, not 
just
+types and exceptions. `LabelCardinality` and its constants (`ONE`, 
`ONE_OR_MORE`,
+`ZERO_OR_MORE`) are a Java-side concept that never appears in the grammar, so 
the
+capability is described in prose instead ("a graph that permits the set of 
labels
+on an element to change"). If a name is not in `Gremlin.g4` and not a `GType`, 
it
+probably does not belong in normative prose.
+
+Type definitions live in `== Types`; per-type Equality, Comparability, and
+Orderability behavior lives in the Comparability chapter. Do not duplicate
+definitions across the two. The `Java reference exception` column of the Errors
+table is the one intentional Java reference in the document.
+
+The document has two parts. The conceptual sections near the top (equality,
+comparability, orderability, equivalence, type promotion) specify the
+cross-cutting behaviors and change rarely. The large `== Steps` section 
documents
+each Gremlin step individually, and that is where most edits land: per-step
+coverage is still incomplete, and new steps, changed semantics, and new 
overloads
+all show up here. Expect to spend your time in `== Steps`, not in the equality 
and
+comparability material.
+
+When adding or revising a step, **follow the per-step template already in 
use.**
+Each step is anchored as `[[<step>-step]]` under a `=== stepName()` heading and
+fills in the same labeled fields, in order:
+
+- `*Description:*` — one or two sentences on what the step does.
+- `*Syntax:*` — each overload as a backticked signature, multiple overloads
+  separated by `|` (for example `` `asString()` | `asString(Scope scope)` ``).
+  Use TypeScript-style `name: TYPE` parameter form with GType names for
+  primitives (`STRING`, `INT`, `BOOLEAN`, etc.), `any` for unconstrained
+  values, and PascalCase for TinkerPop concept types (`Traversal`,
+  `Traverser`, `Scope`, `P`, `T`, `GType`, etc.). Varargs use the trailing
+  ellipsis form (`STRING...`). Document only the overloads that appear in
+  the ANTLR grammar (`gremlin-language/src/main/antlr4/Gremlin.g4`); do
+  not document method-level overloads that exist only as Java
+  `GraphTraversal` sugar.
+- A `[width="100%",options="header"]` table with the columns
+  `Start Step | Mid Step | Modulated | Domain | Range`.
+- `*Arguments:*` — one bullet per argument. (A genuine enumeration, so a list 
is
+  the right choice here.) Use `None` as the body for steps that take no 
arguments.
+- `*Modulation:*` — describes the modulators the step accepts (such as
+  `from()`/`to()` or `by()`). Use `None` as the body for steps that take no
+  modulators.
+- `*Considerations:*` — prose covering edge cases, grammar restrictions, and 
any
+  GLV-specific notes.
+- `*Exceptions:*` — the conditions under which the step raises an error, named 
by
+  the TinkerPop error category rather than a Java exception class. Use `None` 
as
+  the body for steps that raise no errors.
+- A closing `See:` line linking to the step's source file(s) and its reference
+  entry, using the `x.y.z` placeholder.
+
+A new overload usually means adding its signature to `*Syntax:*` and describing
+the new argument under `*Arguments:*`. A semantic change usually means revising
+`*Considerations:*` or `*Exceptions:*`. Match a nearby existing step rather 
than
+inventing a new structure, and fill the gap when documenting a step that has no
+entry yet. When editing an `*Exceptions:*` section, verify the claim against 
the
+step's source class.
+
+---
+
+## Developer Documentation
+
+`docs/src/dev/developer/` — internal notes for contributors (contributing,
+development environment, for-committers, release, administration).
+
+This is in-project material written for people working on TinkerPop itself. The
+formal house style still applies. There is little beyond that to special-case:
+keep it accurate, keep it current with the actual process, and match the
+structure of the surrounding committer documentation.
+
+---
+
+## IO Documentation
+
+`docs/src/dev/io/` — one file per serialization format (`graphbinary.asciidoc`,
+`graphson.asciidoc`, `graphml.asciidoc`, `gryo.asciidoc`).
+
+IO documentation specifies the wire and file formats that providers and 
advanced
+users implement against. It carries the same formal, complete, precise voice as
+Provider documentation. Accuracy is paramount: this is a specification, so type
+mappings, byte layouts, and format versions must match the implementation
+exactly. Match the structure already used for the format being edited rather 
than
+reorganizing it, and keep examples illustrative (`[source,text]` or
+`[source,json]`) rather than executable.
+
+---
+
+## Future Documentation
+
+`docs/src/dev/future/` — numbered design proposals (`proposal-*.asciidoc`) for
+changes under consideration.
+
+Future documentation captures proposed and planned work, so it reads 
differently
+from the rest. A proposal argues for a direction: it lays out motivation, the
+proposed design, alternatives, and open questions. The formal house style still
+applies, but the content is forward-looking and provisional rather than a
+description of how TinkerPop behaves today. When adding a proposal, follow the
+numbering and structure of the existing `proposal-*` files.
diff --git a/.skills/tinker-doc/references/executable-blocks.md 
b/.skills/tinker-doc/references/executable-blocks.md
new file mode 100644
index 0000000000..92e91e31f9
--- /dev/null
+++ b/.skills/tinker-doc/references/executable-blocks.md
@@ -0,0 +1,91 @@
+# Executable Code Blocks
+
+The defining feature of TinkerPop documentation is that most Gremlin examples 
are
+**executed when the docs are built**. Each executable block is fed to a live
+Gremlin Console, run against a real graph, and its actual `==>` output is 
inlined
+automatically. This is what keeps the documentation honest, and it has a direct
+consequence for how examples are written: the author supplies the Gremlin, 
never
+the output.
+
+## Block types
+
+| Block opener | Executed? | Use for                                           
                                                           |
+|---|---|--------------------------------------------------------------------------------------------------------------|
+| `[gremlin-groovy,modern]` | Yes, against the **modern** toy graph | The 
default for most examples                                                       
                         |
+| `[gremlin-groovy,existing]` | Yes, against the **existing** graph | Examples 
that build on or mutate graph state from the immediately previous block         
                    |
+| `[gremlin-groovy]` | Yes, with **no** graph bound | Setup that does not need 
a graph                                                                         
    |
+| `[source,groovy]` | No | Illustrative Groovy that must not run 
(hypotheticals, two-version comparisons); **all upgrade-doc examples** |
+| `[source,text]` | No | Console sessions, error cases, or specification 
examples shown verbatim                                      |
+
+Only `modern` and `existing` are available as graph names. The **modern** graph
+is the standard six-element toy graph used almost everywhere. Reach for 
`existing`
+only when an example genuinely needs to persist or mutate state that a later 
block
+depends on.
+
+### Never invent output
+
+For any **executed** block, write only the Gremlin lines. Do **not** type the
+`==>` result lines yourself. They are filled in automatically. Hand-written 
output
+in an executable block is wrong by definition and will be overwritten or will
+conflict with reality.
+
+Conversely, in a non-executed `[source,text]` or `[source,groovy]` block you
+write the whole thing, prompts and output included, because nothing runs it. 
This
+is how upgrade docs show before/after behavior and how the semantics document
+specifies results.
+
+### Upgrade documentation always uses static blocks
+
+Upgrade documentation must **never** use an executable `[gremlin-groovy]` 
block.
+Every example in the upgrade docs is a static `[source,groovy]` or 
`[source,text]`
+block whose output is written by hand. An upgrade example is a snapshot of how
+something behaved at a particular point in the project's history, frequently
+showing an old version next to a new one. Regenerating it against the current
+build would defeat its purpose, so these examples are deliberately kept static.
+
+## Output suppression: the `;[]` idiom
+
+When a line in an executable block is setup whose output would be noise (a
+variable assignment, a schema-building call), append `;[]` to it. The statement
+still executes, but it returns an empty list, so no `==>` line is emitted:
+
+```
+[gremlin-groovy,modern]
+----
+v1 = g.V(1).next();[]
+v2 = g.V(2).next();[]
+g.V(v1).bothE().where(otherV().is(v2))
+----
+```
+
+Here the two assignments run silently and only the final traversal produces
+visible output.
+
+## Numbered callouts
+
+To explain specific lines without interrupting the example, use AsciiDoc
+callouts. Mark lines with `<1>`, `<2>`, and so on, then list the explanations
+immediately after the block:
+
+```
+[gremlin-groovy,modern]
+----
+g.V(1).bothE()                                   <1>
+g.V(1).bothE().where(otherV().hasId(2))          <2>
+----
+
+<1> There are three edges from the vertex with the identifier of "1".
+<2> Filter those edges with `where()` ...
+```
+
+Align the callout markers into a column for readability, as the existing 
recipes
+do. This is the primary explanatory device in the recipes book.
+
+## The multi-language story
+
+The reference examples are written in Gremlin-Groovy. When documenting a step,
+write the Groovy example. Do not hand-maintain parallel copies in every 
language
+inside a step section unless the surrounding content already does so. The
+dedicated per-language material (connecting, imports, configuration) lives in
+`reference/gremlin-variants.asciidoc`, organized under `[[gremlin-python]]`,
+`[[gremlin-javascript]]`, and similar anchors.
diff --git a/bin/agent-setup.sh b/bin/agent-setup.sh
new file mode 100755
index 0000000000..db09b49eb1
--- /dev/null
+++ b/bin/agent-setup.sh
@@ -0,0 +1,341 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Set up AI coding agent integration with TinkerPop's Agent Skills.
+#
+# TinkerPop maintains Agent Skills in .skills/:
+#   tinker-dev    - Development guidance (coding conventions, build recipes, 
etc.)
+#   tinker-doc    - Documentation authoring and review (voice, per-book style, 
etc.)
+#
+# Different AI coding tools discover skills in different directories. This 
script
+# creates the necessary symlinks or shims so your tool can find the skills.
+#
+# Usage:
+#   bin/agent-setup.sh <agent>
+#   bin/agent-setup.sh --list
+#   bin/agent-setup.sh --all
+#
+# Examples:
+#   bin/agent-setup.sh claude       # Set up for Claude Code
+#   bin/agent-setup.sh kiro         # Set up for Kiro
+#   bin/agent-setup.sh --all        # Set up for all supported agents
+#
+# Supported agents:
+#   claude    - Claude Code (.claude/skills/)
+#   copilot   - GitHub Copilot (.github/skills/ and .agents/skills/)
+#   cursor    - Cursor (.cursor/skills/)
+#   codex     - OpenAI Codex (.codex/skills/)
+#   junie     - JetBrains Junie (.junie/skills/)
+#   kiro      - Kiro (.kiro/skills/)
+
+set -uo pipefail
+
+SKILLS=("tinker-dev" "tinker-doc")
+
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[0;33m'
+NC='\033[0m'
+
+ok()   { echo -e "  ${GREEN}✓${NC} $1"; }
+skip() { echo -e "  ${YELLOW}○${NC} $1"; }
+bad()  { echo -e "  ${RED}✗${NC} $1"; }
+
+usage() {
+    echo "Usage: bin/agent-setup.sh <agent|--list|--all|--contributor [agent]>"
+    echo ""
+    echo "Agents: claude, copilot, cursor, codex, junie, kiro"
+    echo ""
+    echo "Options:"
+    echo "  --list           List supported agents and their skill discovery 
paths"
+    echo "  --all            Set up shims for all supported agents"
+    echo "  --contributor    Also install beads workflow hooks (committers; 
claude, kiro)"
+    echo "  --help           Show this message"
+}
+
+# Verify we're in the repo root
+if [[ ! -d ".skills/tinker-dev" ]]; then
+    bad "Cannot find .skills/tinker-dev — run this script from the TinkerPop 
repository root."
+    exit 1
+fi
+
+# Remove TinkerPop skill entries (symlinks or copies) from a tool's skill
+# directory before the current ones are (re)created. Matching only "tinker*"
+# keeps any custom skills the user maintains intact. Entries for skills that no
+# longer exist (e.g. a renamed "tinkerpop-dev") are reported as stale removals;
+# current skills are cleared silently so the setup step can recreate them
+# cleanly — this also fixes symlinks whose relative target path has changed.
+purge_tinker_skills() {
+    local target_dir="$1"
+    [[ -d "$target_dir" ]] || return 0
+
+    local entry name skill is_current
+    for entry in "$target_dir"/tinker*; do
+        # If the glob matched nothing it stays literal — skip non-existent 
paths.
+        [[ -e "$entry" || -L "$entry" ]] || continue
+        name=$(basename "$entry")
+        is_current=0
+        for skill in "${SKILLS[@]}"; do
+            [[ "$name" == "$skill" ]] && is_current=1 && break
+        done
+        rm -rf "$entry"
+        [[ "$is_current" -eq 0 ]] && skip "removed stale skill 
$target_dir/$name"
+    done
+}
+
+# Create a symlink from a tool's skill directory to our canonical skill
+setup_symlink() {
+    local tool_name="$1"
+    local target_dir="$2"
+    local skill_name="$3"
+    local skill_dir=".skills/$skill_name"
+
+    mkdir -p "$target_dir"
+    local link_path="$target_dir/$skill_name"
+
+    if [[ -L "$link_path" ]]; then
+        skip "$tool_name: symlink already exists at $link_path"
+        return 0
+    fi
+
+    if [[ -e "$link_path" ]]; then
+        bad "$tool_name: $link_path already exists and is not a symlink — 
skipping"
+        return 1
+    fi
+
+    # Compute relative path from target_dir to skill_dir
+    local rel_path
+    rel_path=$(python3 -c "import os.path; print(os.path.relpath('$skill_dir', 
'$target_dir'))" 2>/dev/null)
+    if [[ -z "$rel_path" ]]; then
+        rel_path=$(perl -e 'use File::Spec; print 
File::Spec->abs2rel("'"$skill_dir"'", "'"$target_dir"'")' 2>/dev/null)
+    fi
+    if [[ -z "$rel_path" ]]; then
+        bad "$tool_name: could not compute relative path (need python3 or 
perl)"
+        return 1
+    fi
+
+    ln -s "$rel_path" "$link_path"
+    ok "$tool_name: created symlink $link_path -> $rel_path"
+}
+
+# Kiro doesn't follow symlinks in .kiro/skills/, so we copy the skill directory
+# instead. See: https://github.com/kirodotdev/Kiro/issues (symlink support).
+setup_kiro() {
+    mkdir -p ".kiro/skills"
+    purge_tinker_skills ".kiro/skills"
+    for skill_name in "${SKILLS[@]}"; do
+        local target_dir=".kiro/skills/$skill_name"
+        cp -r ".skills/$skill_name" "$target_dir"
+        ok "kiro: copied $skill_name to $target_dir"
+    done
+    echo ""
+    echo -e "  ${YELLOW}NOTE:${NC} Kiro uses copies, not symlinks. If you 
update skills in"
+    echo -e "        .skills/, re-run this script to sync the changes."
+}
+
+setup_agent() {
+    local agent="$1"
+    case "$agent" in
+        claude)
+            purge_tinker_skills ".claude/skills"
+            for skill in "${SKILLS[@]}"; do
+                setup_symlink "claude" ".claude/skills" "$skill"
+            done
+            ;;
+        copilot)
+            purge_tinker_skills ".github/skills"
+            purge_tinker_skills ".agents/skills"
+            for skill in "${SKILLS[@]}"; do
+                setup_symlink "copilot (.github)" ".github/skills" "$skill"
+                setup_symlink "copilot (.agents)" ".agents/skills" "$skill"
+            done
+            ;;
+        cursor)
+            purge_tinker_skills ".cursor/skills"
+            for skill in "${SKILLS[@]}"; do
+                setup_symlink "cursor" ".cursor/skills" "$skill"
+            done
+            ;;
+        codex)
+            purge_tinker_skills ".codex/skills"
+            for skill in "${SKILLS[@]}"; do
+                setup_symlink "codex" ".codex/skills" "$skill"
+            done
+            ;;
+        junie)
+            purge_tinker_skills ".junie/skills"
+            for skill in "${SKILLS[@]}"; do
+                setup_symlink "junie" ".junie/skills" "$skill"
+            done
+            ;;
+        kiro)
+            setup_kiro
+            ;;
+        *)
+            bad "Unknown agent: $agent"
+            echo ""
+            usage
+            return 1
+            ;;
+    esac
+}
+
+# --- Contributor hooks (opt-in) ---------------------------------------------
+#
+# Beads is a committer tool, so hook wiring is opt-in via --contributor. The
+# logic lives in bin/beads-agent-hook.sh; the JSON under bin/agent-hooks/ only
+# names events and invokes it. Installs are idempotent: our entries are found
+# by their beads-agent-hook.sh reference (claude) or tinkerpop-beads- name
+# prefix (kiro), removed, then rewritten.
+
+HOOK_AGENTS=("claude" "kiro")
+
+setup_claude_hooks() {
+    local settings=".claude/settings.local.json"
+    mkdir -p ".claude"
+    [[ -f "$settings" ]] || echo '{}' > "$settings"
+
+    if ! python3 - "$settings" "bin/agent-hooks/claude.json" <<'PY'
+import json, sys
+
+settings_path, hooks_path = sys.argv[1], sys.argv[2]
+with open(settings_path) as fh:
+    settings = json.load(fh)
+with open(hooks_path) as fh:
+    ours = {k: v for k, v in json.load(fh)["hooks"].items()}
+
+MARKER = "beads-agent-hook.sh"
+
+
+def is_ours(entry):
+    return any(MARKER in h.get("command", "") for h in entry.get("hooks", []))
+
+
+# Sweep every event, not just the ones we are about to write: an event we no
+# longer wire (PreCompact, once) must not be orphaned in the user's settings.
+existing = settings.setdefault("hooks", {})
+for event in list(existing):
+    kept = [e for e in existing[event] if not is_ours(e)]
+    if kept:
+        existing[event] = kept
+    else:
+        del existing[event]
+
+for event, entries in ours.items():
+    existing[event] = existing.get(event, []) + entries
+
+with open(settings_path, "w") as fh:
+    json.dump(settings, fh, indent=2)
+    fh.write("\n")
+PY
+    then
+        bad "claude: could not merge hooks into $settings"
+        return 1
+    fi
+    ok "claude: merged beads hooks into $settings (SessionStart, Stop, 
UserPromptSubmit)"
+}
+
+setup_kiro_hooks() {
+    mkdir -p ".kiro/hooks"
+    cp "bin/agent-hooks/kiro.json" ".kiro/hooks/tinkerpop-beads.json"
+    ok "kiro: wrote .kiro/hooks/tinkerpop-beads.json (SessionStart, Stop, 
UserPromptSubmit)"
+}
+
+setup_hooks() {
+    local agent="$1"
+
+    if ! command -v bd >/dev/null 2>&1; then
+        skip "$agent: 'bd' not found — hooks installed anyway, they stay 
silent without it"
+    fi
+
+    case "$agent" in
+        claude) setup_claude_hooks ;;
+        kiro)   setup_kiro_hooks ;;
+        *)
+            bad "No hook support for: $agent"
+            echo "  Hooks are available for: ${HOOK_AGENTS[*]}"
+            return 1
+            ;;
+    esac
+}
+
+list_agents() {
+    echo "Supported agents and their skill discovery paths:"
+    echo ""
+    echo "  Skills: ${SKILLS[*]}"
+    echo ""
+    echo "  claude    .claude/skills/<skill>/     -> symlink to 
.skills/<skill>"
+    echo "  copilot   .github/skills/<skill>/     -> symlink to 
.skills/<skill>"
+    echo "            .agents/skills/<skill>/     -> symlink to 
.skills/<skill>"
+    echo "  cursor    .cursor/skills/<skill>/     -> symlink to 
.skills/<skill>"
+    echo "  codex     .codex/skills/<skill>/      -> symlink to 
.skills/<skill>"
+    echo "  junie     .junie/skills/<skill>/      -> symlink to 
.skills/<skill>"
+    echo "  kiro      .kiro/skills/<skill>/       -> copy of .skills/<skill> 
(re-run to sync)"
+}
+
+# --- Main ---
+
+if [[ $# -eq 0 ]]; then
+    usage
+    exit 1
+fi
+
+case "$1" in
+    --help|-h)
+        usage
+        ;;
+    --list)
+        list_agents
+        ;;
+    --all)
+        echo "Setting up all agent integrations..."
+        echo ""
+        for agent in claude copilot cursor codex junie kiro; do
+            setup_agent "$agent"
+        done
+        echo ""
+        echo "Done. Symlinked directories and generated files are gitignored."
+        echo "Add them to .gitignore if they aren't already."
+        ;;
+    --contributor)
+        shift
+        if [[ $# -eq 0 ]]; then
+            echo "Setting up beads hooks for all supported agents..."
+            echo ""
+            for agent in "${HOOK_AGENTS[@]}"; do
+                setup_hooks "$agent"
+            done
+        else
+            echo "Setting up beads hooks for $1..."
+            echo ""
+            setup_hooks "$1"
+        fi
+        echo ""
+        echo "Hooks are advisory — they remind, they never block. Logic lives 
in"
+        echo "bin/beads-agent-hook.sh; run it directly to see what an agent is 
shown:"
+        echo ""
+        echo "  bin/beads-agent-hook.sh stop"
+        ;;
+    *)
+        echo "Setting up $1..."
+        echo ""
+        setup_agent "$1"
+        ;;
+esac

Reply via email to