Skip to content

Commit 9ce2102

Browse files
authored
Merge pull request #203 from cpoepke/main
feat: add semantic-anchors Claude Code plugin with onboarding skill and pre-commit sync
2 parents 4ca7eb3 + cf46d39 commit 9ce2102

8 files changed

Lines changed: 226 additions & 0 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3+
"name": "semantic-anchors",
4+
"description": "Semantic anchor skills for LLM and coding-agent onboarding, including a first-start Claude onboarding prompt",
5+
"owner": {
6+
"name": "LLM Coding",
7+
"url": "https://github.com/LLM-Coding"
8+
},
9+
"plugins": [
10+
{
11+
"name": "semantic-anchors",
12+
"description": "Semantic anchor skills for translating established methodologies, prompting first-run Claude onboarding, and installing persistent coding-agent context.",
13+
"version": "0.1.0",
14+
"author": {
15+
"name": "LLM Coding",
16+
"url": "https://github.com/LLM-Coding"
17+
},
18+
"source": "./plugins/semantic-anchors",
19+
"category": "productivity",
20+
"homepage": "https://github.com/LLM-Coding/Semantic-Anchors"
21+
}
22+
]
23+
}

.githooks/pre-commit

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
set -e
3+
# Pre-commit hook: sync skill/ -> plugins/semantic-anchors/skills/
4+
#
5+
# Overwrites the plugin skills directory from the canonical skill/ source so
6+
# the two never diverge in a commit.
7+
#
8+
# Works on Unix/macOS and Windows (Git Bash / Git for Windows).
9+
# No dependencies beyond sh and the standard Git installation.
10+
11+
REPO_ROOT="$(git rev-parse --show-toplevel)"
12+
13+
# Run the sync (rm -rf + cp -R each skill directory)
14+
sh "$REPO_ROOT/scripts/sync-claude-plugin.sh"
15+
16+
# Stage the result so the overwritten files are included in this commit
17+
git -C "$REPO_ROOT" add -- plugins/semantic-anchors/skills/

CLAUDE.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ This repository is a curated catalog of **semantic anchors** - well-defined term
88

99
**Current Status:** The repository is undergoing a major redesign to become an interactive, bilingual website with treemap visualization, role-based filtering, and automated contribution workflow.
1010

11+
## First-Time Setup
12+
13+
After cloning, activate the shared Git hooks with one command (works on Unix/macOS and Windows Git Bash):
14+
15+
```bash
16+
git config core.hooksPath .githooks
17+
```
18+
19+
This installs the pre-commit hook that automatically syncs `skill/` into `plugins/semantic-anchors/skills/` on every commit. No other tools are required.
20+
1121
## Git Workflow & Fork Setup
1222

1323
**Development takes place in the fork until PRD implementation is complete.**
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"description": "Semantic anchor onboarding prompt",
3+
"hooks": {
4+
"SessionStart": [
5+
{
6+
"matcher": "startup|resume",
7+
"hooks": [
8+
{
9+
"type": "command",
10+
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/prompt-onboarding.sh"
11+
}
12+
]
13+
}
14+
]
15+
}
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "semantic-anchors",
3+
"version": "0.1.0",
4+
"description": "Semantic anchor skills for translating terminology, prompting first-run Claude onboarding, and installing persistent anchor context into coding agents.",
5+
"author": {
6+
"name": "LLM Coding",
7+
"url": "https://github.com/LLM-Coding"
8+
},
9+
"repository": "https://github.com/LLM-Coding/Semantic-Anchors",
10+
"keywords": ["semantic-anchors", "prompting", "llm", "codex", "claude-code", "gemini"],
11+
"skills": "./skills/"
12+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
#!/bin/bash
2+
# Claude SessionStart hook that prompts for semantic-anchor onboarding
3+
# when no managed anchor block is present yet.
4+
5+
set -euo pipefail
6+
7+
command -v python3 >/dev/null 2>&1 || { echo "Error: python3 is required but not found" >&2; exit 1; }
8+
9+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$PWD}"
10+
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
11+
STATE_DIR="$HOME/.claude/semantic-anchor-onboarding"
12+
STATE_FILE="$STATE_DIR/state.json"
13+
MARKER_START="<!-- semantic-anchors:start -->"
14+
MARKER_END="<!-- semantic-anchors:end -->"
15+
COOLDOWN_HOURS=24
16+
17+
has_marker() {
18+
local file
19+
for file in "$@"; do
20+
if [ -f "$file" ] &&
21+
grep -qF "$MARKER_START" "$file" &&
22+
grep -qF "$MARKER_END" "$file"; then
23+
return 0
24+
fi
25+
done
26+
return 1
27+
}
28+
29+
if has_marker \
30+
"$PROJECT_DIR/AGENTS.md" \
31+
"$PROJECT_DIR/CLAUDE.md" \
32+
"$PROJECT_DIR/GEMINI.md" \
33+
"$PROJECT_DIR/.github/copilot-instructions.md" \
34+
"$PROJECT_DIR/.claude/AGENTS.md" \
35+
"$HOME/.claude/CLAUDE.md" \
36+
"$CODEX_HOME_DIR/AGENTS.md" \
37+
"$HOME/.gemini/GEMINI.md"; then
38+
exit 0
39+
fi
40+
41+
mkdir -p "$STATE_DIR" 2>/dev/null || true
42+
43+
python3 - "$STATE_FILE" "$PROJECT_DIR" "$COOLDOWN_HOURS" <<'PY'
44+
import json
45+
import os
46+
import sys
47+
import tempfile
48+
from datetime import datetime, timedelta, timezone
49+
50+
state_path, project_dir, cooldown_hours = sys.argv[1], sys.argv[2], int(sys.argv[3])
51+
now = datetime.now(timezone.utc)
52+
53+
try:
54+
with open(state_path, "r", encoding="utf-8") as handle:
55+
state = json.load(handle)
56+
except (FileNotFoundError, json.JSONDecodeError, OSError):
57+
state = {}
58+
59+
projects = state.setdefault("projects", {})
60+
entry = projects.setdefault(project_dir, {})
61+
last_prompt_raw = entry.get("last_prompt")
62+
63+
if last_prompt_raw:
64+
try:
65+
last_prompt = datetime.fromisoformat(last_prompt_raw.replace("Z", "+00:00"))
66+
except (ValueError, TypeError):
67+
last_prompt = None
68+
if last_prompt and now - last_prompt < timedelta(hours=cooldown_hours):
69+
raise SystemExit(0)
70+
71+
entry["last_prompt"] = now.isoformat().replace("+00:00", "Z")
72+
73+
tmp_path = None
74+
try:
75+
state_dir = os.path.dirname(state_path)
76+
fd, tmp_path = tempfile.mkstemp(dir=state_dir, suffix=".tmp")
77+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
78+
json.dump(state, handle, indent=2)
79+
handle.write("\n")
80+
os.replace(tmp_path, state_path)
81+
except OSError:
82+
# Best-effort: if write fails, skip silently rather than breaking the hook
83+
if tmp_path and os.path.exists(tmp_path):
84+
os.unlink(tmp_path)
85+
86+
message = (
87+
"Semantic anchors are not configured for this workspace. "
88+
"On your next response, ask one short onboarding question: "
89+
"whether the user wants to onboard semantic anchors now for this project "
90+
"or for their home directory. If they agree and the semantic-anchor-onboarding "
91+
"skill is available, use it; otherwise guide them to the installation instructions "
92+
"in the repository README."
93+
)
94+
95+
payload = {
96+
"hookSpecificOutput": {
97+
"hookEventName": "SessionStart",
98+
"additionalContext": message,
99+
}
100+
}
101+
print(json.dumps(payload))
102+
PY

plugins/semantic-anchors/tile.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "semantic-anchors",
3+
"version": "0.1.0",
4+
"summary": "Semantic anchor skills for translating established methodologies, prompting first-run Claude onboarding, and installing persistent coding-agent context.",
5+
"skills": {
6+
"semantic-anchor-translator": {
7+
"path": "skills/semantic-anchor-translator/SKILL.md"
8+
},
9+
"semantic-anchor-onboarding": {
10+
"path": "skills/semantic-anchor-onboarding/SKILL.md"
11+
}
12+
}
13+
}

scripts/sync-claude-plugin.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/sh
2+
# Sync generic skills into the Claude plugin package.
3+
4+
set -eu
5+
6+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7+
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
8+
SOURCE_DIR="$REPO_ROOT/skill"
9+
PLUGIN_SKILLS_DIR="$REPO_ROOT/plugins/semantic-anchors/skills"
10+
11+
# Safety: validate paths before destructive operations
12+
case "$PLUGIN_SKILLS_DIR" in
13+
*/plugins/semantic-anchors/skills) ;;
14+
*) echo "ERROR: unexpected PLUGIN_SKILLS_DIR: $PLUGIN_SKILLS_DIR" >&2; exit 1 ;;
15+
esac
16+
17+
if [ ! -d "$SOURCE_DIR" ]; then
18+
echo "WARN: source directory does not exist: $SOURCE_DIR (sync skipped)" >&2
19+
exit 0
20+
fi
21+
22+
mkdir -p "$PLUGIN_SKILLS_DIR"
23+
24+
# Remove all existing skill subdirectories so deletions in skill/ are reflected
25+
find "$PLUGIN_SKILLS_DIR" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} +
26+
27+
for skill_dir in "$SOURCE_DIR"/*; do
28+
[ -d "$skill_dir" ] || continue
29+
skill_name="$(basename "${skill_dir:?}")"
30+
cp -R "$skill_dir" "${PLUGIN_SKILLS_DIR:?}/$skill_name"
31+
done
32+
33+
echo "Synced skills into $PLUGIN_SKILLS_DIR"

0 commit comments

Comments
 (0)