Skip to content

Commit 6f79732

Browse files
authored
feat(evolve-lite): add entity sharing skills and CI tests (#188)
* feat(evolve-lite): add entity sharing skills and CI tests New skills: publish, subscribe, unsubscribe, sync New lib modules: config.py, audit.py Updated: plugin.json, hooks.json, entity_io.py, save_entities.py, retrieve_entities.py CI test suite (110 tests in tests/platform_integrations/): - test_config.py, test_audit.py, test_entity_io_core.py - test_publish.py, test_subscribe.py, test_sync.py - test_retrieve.py, test_save_entities.py, test_plugin_structure.py * Addresses CodeRabbit review findings
1 parent 436cbdd commit 6f79732

29 files changed

Lines changed: 2442 additions & 16 deletions

File tree

platform-integrations/claude/plugins/evolve-lite/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "evolve-lite",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Learn from conversations with auto-generated entities",
55
"author": {
66
"name": "Vinod Muthusamy"

platform-integrations/claude/plugins/evolve-lite/README.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,90 @@ You can also manually invoke `/evolve-lite:learn` at any time.
5555
> - Set a specific `"matcher"` string to restrict triggering to prompts that contain that text.
5656
> - Reduce `"timeout"` to cap how long the learn step can run.
5757
58+
## Sharing Guidelines
59+
60+
Evolve Lite supports sharing guidelines between users via public Git repositories. You can publish your own guidelines so others can subscribe to them, and subscribe to guidelines published by others.
61+
62+
### Setup
63+
64+
Sharing requires an `evolve.config.yaml` at the project root. If it doesn't exist, the subscribe or publish skills will prompt you to create one. Minimal structure:
65+
66+
```yaml
67+
identity:
68+
user: yourname # used to stamp ownership on published guidelines
69+
public_repo:
70+
remote: git@github.com:yourname/evolve-guidelines.git
71+
branch: main
72+
subscriptions: []
73+
sync:
74+
on_session_start: true # auto-sync on each session start
75+
```
76+
77+
The `.evolve/` directory is kept out of version control — the skills automatically add it to `.gitignore`.
78+
79+
### Publishing Guidelines
80+
81+
Use `/evolve-lite:publish` to share one or more of your local guidelines with others:
82+
83+
1. The skill lists files in `.evolve/entities/guideline/`
84+
2. You pick which ones to publish
85+
3. Each selected file is copied to `.evolve/public/`, stamped with your username as the owner, committed, and pushed to your `public_repo.remote`
86+
87+
Others can then subscribe using that remote URL.
88+
89+
### Subscribing to Guidelines
90+
91+
Use `/evolve-lite:subscribe` to pull in guidelines from another user's public repo:
92+
93+
```text
94+
/evolve-lite:subscribe
95+
> Remote URL: git@github.com:alice/evolve-guidelines.git
96+
> Short name: alice
97+
```
98+
99+
The repo is cloned to `.evolve/subscribed/alice/` and mirrored into `.evolve/entities/subscribed/alice/` so recall picks them up immediately.
100+
101+
### Syncing Subscriptions
102+
103+
Use `/evolve-lite:sync` to pull the latest changes from all subscribed repos:
104+
105+
```text
106+
/evolve-lite:sync
107+
> Synced 2 repo(s): alice (+2 added, 0 updated, 0 removed), bob (+0 added, 1 updated, 0 removed)
108+
```
109+
110+
If `sync.on_session_start: true` is set in config, this runs automatically at the start of each session.
111+
112+
> **Note:** Sync uses `git fetch` + `git reset --hard` on each cloned subscription repo, so local state always matches the remote exactly. Accidentally deleted or modified files are automatically restored on the next sync.
113+
114+
### Unsubscribing
115+
116+
Use `/evolve-lite:unsubscribe` to remove a subscription and delete its locally cloned files:
117+
118+
```text
119+
/evolve-lite:unsubscribe
120+
> Which subscription would you like to remove?
121+
> 1. alice
122+
> 2. bob
123+
```
124+
125+
The skill confirms before deleting `.evolve/subscribed/{name}/` and its mirror under `.evolve/entities/subscribed/{name}/`.
126+
127+
### Sharing Storage Layout
128+
129+
```text
130+
.evolve/
131+
public/ # git repo pushed to your public remote
132+
guideline-name.md # owner-stamped guideline
133+
subscribed/
134+
alice/ # git clone of alice's public repo
135+
her-guideline.md
136+
entities/
137+
subscribed/
138+
alice/ # mirrored for recall
139+
her-guideline.md
140+
```
141+
58142
## Example Walkthrough
59143

60144
See the [Evolve Lite guide](../../../../docs/integrations/claude/evolve-lite.md#example-walkthrough) for a step-by-step example showing the full learn-then-recall loop across two sessions.

platform-integrations/claude/plugins/evolve-lite/hooks/hooks.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
]
1212
}
1313
],
14+
"SessionStart": [
15+
{
16+
"matcher": "",
17+
"hooks": [
18+
{
19+
"type": "command",
20+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/skills/sync/scripts/sync.py --quiet"
21+
}
22+
]
23+
}
24+
],
1425
"Stop": [
1526
{
1627
"matcher": "",
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
"""Append-only audit log writer for .evolve/audit.log."""
2+
3+
import datetime
4+
import json
5+
import pathlib
6+
7+
8+
def append(project_root=".", **fields):
9+
"""Append a JSON audit entry to .evolve/audit.log.
10+
11+
Args:
12+
project_root: Root directory that contains .evolve/.
13+
**fields: Arbitrary key-value fields to include in the log entry.
14+
"""
15+
path = pathlib.Path(project_root) / ".evolve" / "audit.log"
16+
path.parent.mkdir(parents=True, exist_ok=True)
17+
entry = {**fields, "ts": datetime.datetime.now(datetime.UTC).isoformat().replace("+00:00", "Z")}
18+
with path.open("a", encoding="utf-8") as f:
19+
f.write(json.dumps(entry) + "\n")
20+
21+
22+
if __name__ == "__main__":
23+
import tempfile
24+
25+
with tempfile.TemporaryDirectory() as d:
26+
append(project_root=d, action="test", actor="alice")
27+
log_path = __import__("pathlib").Path(d) / ".evolve" / "audit.log"
28+
line = log_path.read_text(encoding="utf-8").strip()
29+
entry = __import__("json").loads(line)
30+
assert entry["action"] == "test"
31+
assert entry["actor"] == "alice"
32+
assert "ts" in entry
33+
print("audit.py ok")

0 commit comments

Comments
 (0)