You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a small `git` plugin as a configuration point for non-observability
git concerns — currently just operator attribution; intended to grow
into a home for other git-related hooks, config, and tooling.
Why a separate plugin: the observability plugin owns git event-emission
hooks (post-commit, pre-push, …) and that's its job. This plugin holds
non-observability git concerns so the two stay focused and can evolve
independently.
Changes:
- Add plugins/git/.claude-plugin/plugin.json declaring SYN_OPERATOR_NAME
and SYN_OPERATOR_EMAIL via requires_env so the agentic-isolation
orchestrator auto-forwards them when set in the host env.
- Add plugins/git/hooks/prepare-commit-msg — appends
'Co-authored-by: NAME <EMAIL>' when both operator env vars are set.
Skips merge/squash/template/commit message sources. Idempotent.
Strips CR/LF from operator inputs to prevent newline-injection of
extra trailers. No-op when env vars unset (backward compatible).
- Add plugins/git/README.md framing the plugin's scope.
- Update providers/workspaces/claude-cli/manifest.yaml to bake the
new plugin into the image.
- Update entrypoint.sh: compose git hooks from BOTH observability
(event emission) and the new git plugin (attribution) into a single
runtime directory at $HOME/.git-hooks, then point core.hooksPath
there. Multiple plugins can now contribute git hooks. Observability
is otherwise untouched.
Resolves#158.
Verification (rebuilt 2.1.126 image):
- 27/27 just test-workspace passes.
- Hook composition: 6 symlinks under $HOME/.git-hooks/ — 5 to
observability/hooks/git/, 1 to git/hooks/prepare-commit-msg.
- prepare-commit-msg matrix in container:
- merge|squash|template|commit source -> no trailer
- message source, no env -> no trailer
- message source, with env -> trailer appended
- trailer already present -> idempotent
- newline-injected env var -> sanitized, only 1 trailer line
- Observability git_commit events still emit on stderr as before.
"description": "Git configuration point for the workspace — non-observability git concerns. Currently owns operator Co-authored-by attribution; intended to grow into a home for other git-related hooks, config, and tooling.",
"description": "Operator display name. When set together with SYN_OPERATOR_EMAIL, every workspace commit gets a 'Co-authored-by' trailer attributing the operator who sponsored the workspace.",
10
+
"required": false,
11
+
"secret": false
12
+
},
13
+
"SYN_OPERATOR_EMAIL": {
14
+
"description": "Operator email — must match a verified GitHub account so the co-author renders with the operator's avatar on PRs.",
Git configuration point for the workspace — a home for **non-observability** git concerns: hooks, config, and tooling that affect how the agent interacts with git, but aren't about emitting events.
4
+
5
+
> **Why a separate plugin?** The `observability` plugin owns git hooks that emit events (`post-commit`, `pre-push`, etc.) — that's its job. This plugin holds everything else git-related so observability stays focused. Both plugins can ship git hooks; the workspace entrypoint composes them into a single `core.hooksPath` at startup.
6
+
7
+
## What's here today
8
+
9
+
-**`hooks/prepare-commit-msg`** — operator `Co-authored-by:` attribution. When `SYN_OPERATOR_NAME` and `SYN_OPERATOR_EMAIL` are both set, the hook appends a co-author trailer to every commit message so PRs the workspace opens are attributed to the operator who sponsored it.
10
+
11
+
## Operator attribution
12
+
13
+
Two env vars enable the trailer:
14
+
15
+
-`SYN_OPERATOR_NAME` — display name (e.g. `"NeuralEmpowerment"`)
16
+
-`SYN_OPERATOR_EMAIL` — must match a verified GitHub account so the co-author renders with the operator's avatar
17
+
18
+
Both are declared in `requires_env` of `.claude-plugin/plugin.json`, so an `agentic-isolation` orchestrator that has them in the host env will auto-forward them into the container.
19
+
20
+
When unset, the hook is a no-op — backward-compatible.
21
+
22
+
The hook skips auto-generated message sources (`merge`, `squash`, `template`, `commit`) to avoid polluting them, and is idempotent (won't double-append the same trailer).
0 commit comments