mirror of
https://github.com/microsoft/SkillOpt.git
synced 2026-08-03 07:02:46 +08:00
Merge pull request #148 from detailobsessed/feat/devin-session-end-hook
feat(devin): add SessionEnd hook + install script
This commit is contained in:
@@ -16,7 +16,10 @@ source into the Claude Code-compatible JSONL the engine reads.
|
||||
| `harvest_devin.py` | converts Devin ATIF-v1.7 transcripts + agentmemory + `.devin/skills` into JSONL, with `taskKey` + outcome envelopes |
|
||||
| `judge.py` | reference judge for the deferred/judge branch of the validation gate |
|
||||
| `mcp-config.example.json` | drop-in MCP server config |
|
||||
| `devin-rules.snippet.md` | paste into `.devin/rules/skillopt-sleep.md` |
|
||||
| `install.sh` | copies hooks + rules into a project's `.devin/` and prints the MCP registration command |
|
||||
| `devin-rules.snippet.md` | copied to `.devin/rules/skillopt-sleep.md` by `install.sh` |
|
||||
| `hooks/hooks.v1.json` | SessionEnd hook config — copied to `.devin/hooks.v1.json` by `install.sh` |
|
||||
| `hooks/on-session-end.sh` | best-effort activity marker script (called by the hook) |
|
||||
|
||||
## What it harvests
|
||||
|
||||
@@ -33,10 +36,20 @@ After `sleep_adopt`, the evolved skill is synced to `.devin/skills/skillopt-slee
|
||||
|
||||
Requires Python ≥ 3.10. No third-party packages — the server is pure stdlib.
|
||||
|
||||
1. **Register the MCP server.** Use `mcp-config.example.json` as a template; set
|
||||
`args` to the absolute path of this `mcp_server.py`. The engine is found
|
||||
automatically (this plugin lives inside the SkillOpt repo). Or via the Devin
|
||||
CLI:
|
||||
1. **Install hooks + rules into your project.** From the repo root:
|
||||
|
||||
```bash
|
||||
bash plugins/devin/install.sh /path/to/your/project
|
||||
```
|
||||
|
||||
This copies the SessionEnd hook and rules snippet into the project's
|
||||
`.devin/` directory and prints the MCP registration command. The hook is
|
||||
on by default — it logs a cheap activity marker when each session ends so
|
||||
the next nightly cycle knows there is fresh data to harvest. It is
|
||||
non-blocking and spends no API budget. Re-run the script to update.
|
||||
|
||||
2. **Register the MCP server.** Use `mcp-config.example.json` as a template, or
|
||||
run the command printed by `install.sh`:
|
||||
|
||||
```bash
|
||||
devin mcp add skillopt-sleep \
|
||||
@@ -44,9 +57,6 @@ Requires Python ≥ 3.10. No third-party packages — the server is pure stdlib.
|
||||
-- python3 /abs/path/to/SkillOpt/plugins/devin/mcp_server.py
|
||||
```
|
||||
|
||||
2. **(Optional)** copy `devin-rules.snippet.md` to `.devin/rules/skillopt-sleep.md`
|
||||
so Devin proactively offers the tools.
|
||||
|
||||
3. Ask Devin: *"run the sleep cycle"*, *"what did the last sleep propose?"*, *"adopt it"*.
|
||||
|
||||
## Tools
|
||||
|
||||
14
plugins/devin/hooks/hooks.v1.json
Normal file
14
plugins/devin/hooks/hooks.v1.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"SessionEnd": [
|
||||
{
|
||||
"matcher": "",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "\"${DEVIN_PROJECT_DIR}/.devin/hooks/on-session-end.sh\"",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
20
plugins/devin/hooks/on-session-end.sh
Executable file
20
plugins/devin/hooks/on-session-end.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# SkillOpt-Sleep SessionEnd hook for Devin (best-effort, NON-BLOCKING).
|
||||
#
|
||||
# This does NOT run the optimizer. It only appends a tiny marker so the next
|
||||
# nightly cycle knows there is fresh activity to harvest, and (optionally)
|
||||
# nudges the user once that a sleep cycle is available. It must never fail the
|
||||
# session or spend API budget.
|
||||
#
|
||||
# Install: copy this file and hooks.v1.json into your project's .devin/hooks/
|
||||
# directory. Devin CLI reads .devin/hooks.v1.json automatically.
|
||||
set -uo pipefail
|
||||
|
||||
STATE_DIR="${HOME}/.skillopt-sleep"
|
||||
mkdir -p "$STATE_DIR" 2>/dev/null || exit 0
|
||||
|
||||
# Record that a session just ended (cheap; used for "is there new data?").
|
||||
printf '%s\t%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "${DEVIN_PROJECT_DIR:-${PWD}}" \
|
||||
>> "$STATE_DIR/session-end.log" 2>/dev/null || true
|
||||
|
||||
exit 0
|
||||
59
plugins/devin/install.sh
Executable file
59
plugins/devin/install.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Install the SkillOpt-Sleep Devin integration into a project.
|
||||
# Copies the SessionEnd hook and rules snippet into .devin/, and prints
|
||||
# the MCP server registration command. Idempotent.
|
||||
set -euo pipefail
|
||||
|
||||
PLUGIN_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$PLUGIN_DIR/../.." && pwd)"
|
||||
PROJECT="${1:-$(pwd)}"
|
||||
|
||||
echo "[install] repo: $REPO_ROOT"
|
||||
echo "[install] project: $PROJECT"
|
||||
|
||||
DEVIN_DIR="$PROJECT/.devin"
|
||||
mkdir -p "$DEVIN_DIR/hooks" "$DEVIN_DIR/rules"
|
||||
|
||||
# 1) SessionEnd hook (on by default — provides activity signal for nightly harvest)
|
||||
# Merge into existing hooks.v1.json instead of overwriting, so we don't
|
||||
# destroy other project hooks.
|
||||
HOOK_SCRIPT_SRC="$PLUGIN_DIR/hooks/on-session-end.sh"
|
||||
HOOK_SCRIPT_DST="$DEVIN_DIR/hooks/on-session-end.sh"
|
||||
cp "$HOOK_SCRIPT_SRC" "$HOOK_SCRIPT_DST"
|
||||
chmod +x "$HOOK_SCRIPT_DST"
|
||||
echo "[install] hook script -> $HOOK_SCRIPT_DST"
|
||||
|
||||
HOOK_CONFIG="$DEVIN_DIR/hooks.v1.json"
|
||||
if [ -f "$HOOK_CONFIG" ]; then
|
||||
# Merge our SessionEnd hook into the existing config (jq deep-merge)
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq -s '.[0] * .[1]' "$HOOK_CONFIG" "$PLUGIN_DIR/hooks/hooks.v1.json" > "$HOOK_CONFIG.tmp"
|
||||
mv "$HOOK_CONFIG.tmp" "$HOOK_CONFIG"
|
||||
echo "[install] session-end hook -> $HOOK_CONFIG (merged)"
|
||||
else
|
||||
echo "[install] WARNING: jq not found; cannot merge into existing $HOOK_CONFIG"
|
||||
echo "[install] Merge this SessionEnd hook manually or install jq:"
|
||||
echo "[install] cat $PLUGIN_DIR/hooks/hooks.v1.json"
|
||||
echo "[install] Skipping hook config to avoid overwriting existing hooks."
|
||||
fi
|
||||
else
|
||||
cp "$PLUGIN_DIR/hooks/hooks.v1.json" "$HOOK_CONFIG"
|
||||
echo "[install] session-end hook -> $HOOK_CONFIG"
|
||||
fi
|
||||
|
||||
# 2) Rules snippet so Devin proactively offers the tools
|
||||
cp "$PLUGIN_DIR/devin-rules.snippet.md" "$DEVIN_DIR/rules/skillopt-sleep.md"
|
||||
echo "[install] rules snippet -> $DEVIN_DIR/rules/skillopt-sleep.md"
|
||||
|
||||
# 3) Print the MCP server registration command
|
||||
cat <<EOF
|
||||
|
||||
[install] Register the MCP server (run once per machine):
|
||||
|
||||
devin mcp add skillopt-sleep \\
|
||||
--env "SKILLOPT_DEVIN_CLAUDE_HOME=\$HOME/.skillopt-sleep-devin" \\
|
||||
-- python3 $PLUGIN_DIR/mcp_server.py
|
||||
|
||||
Done. Try asking Devin:
|
||||
Run the sleep cycle for this project.
|
||||
EOF
|
||||
Reference in New Issue
Block a user