feat: SkillNote × OpenClaw foundation (v0.4.0)#29
Open
latentloop07 wants to merge 46 commits intomasterfrom
Open
feat: SkillNote × OpenClaw foundation (v0.4.0)#29latentloop07 wants to merge 46 commits intomasterfrom
latentloop07 wants to merge 46 commits intomasterfrom
Conversation
…skills.embedding Adds 0015_openclaw_foundation migration: - CREATE EXTENSION vector (pgvector) - skills.embedding vector(1536) + HNSW cosine index - skill_usage_events table for openclaw usage logging - comments table extended with author_type, comment_type, rating, linked_usage_id Bumps docker-compose postgres image to pgvector/pgvector:pg16. Adds pgvector, openai, numpy to backend deps. Part of SkillNote × OpenClaw foundation (v0.4.0). See docs/superpowers/plans/2026-04-26-skillnote-openclaw-v2.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…events.id Python-side default=uuid.uuid4 in op.create_table is a no-op; only server_default is honored by the DB. Without this, raw inserts that omit id would fail. Matches pattern in 0001_initial. Code review on f20e911. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
….embedding - New model: SkillUsageEvent (mirrors 0015 migration, JSONB metadata_json) - Skill.embedding: Vector(1536), nullable - Comment: +author_type, +comment_type, +rating, +linked_usage_id - Collection.usage_events relationship Part of SkillNote x OpenClaw foundation. See plan task 2.
…e hints Drop unused Integer import, drop sa alias (use bare text), tighten Mapped[list] -> Mapped[list[str]] and Mapped[dict | None] -> Mapped[dict[str, Any] | None]. Code review on b390445.
- Settings: embedding_provider/api_key/model/dim - Service: embed_text (LRU cached), embed_batch, skill_embedding_text - Provider dispatch for openai + voyage with shape/dim guards - Startup warning when SKILLNOTE_EMBEDDING_API_KEY is unset - 7 unit tests with monkeypatched provider (no real API calls) Part of SkillNote × OpenClaw foundation. See plan task 2.5.
- Drop dead-weight SHA256 in LRU cache key (text alone uniquely keys) - Wire the existing logger: info on successful batch, warning on provider error - Move embedding_service import to top of main.py (no circular risk) - Add 2 direct-call tests covering OpenAI provider dimension guard Code review on 0b0d17c. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…nt fields - New openclaw.py: ContextBundleRequest/Skill/Collection/Response, UsageEventCreate/Out - Comment: +author_type/comment_type/rating/linked_usage_id with agent-requires-comment_type validator Part of SkillNote x OpenClaw foundation. See plan task 3.
- UsageEventOut.skill_ids: list[str] (matches JSONB storage; avoids coercion 500s on legacy data; UsageEventCreate keeps UUID validation) - ContextBundleRequest.task_summary + UsageEventCreate.agent_name/task_summary: strip whitespace and reject empty-after-strip - comment.py: stdlib imports before pydantic Code review on 0271cab.
Skill.collections is ARRAY(Text) — a skill belongs to many collections. Originally schema had collection_id (singular); reality is collections (list). Caught while implementing context-bundle endpoint.
…ine ranking - Embedding-guarded (503 if SKILLNOTE_EMBEDDING_API_KEY unset, 502 on provider error) - Single ranked query via Skill.embedding.cosine_distance ordered ASC - Skills with NULL embedding excluded (forces backfill) - 4 aggregation queries pre-loaded into dicts: usage_30d, rating_avg, latest comment, deprecation flag - staleness_status: rule-based (deprecation OR rating<3.0 -> needs_review) - 11 integration tests including N+1 sentinel (<=6 queries) - Router NOT yet registered in main.py - that's Task 7 Part of SkillNote x OpenClaw foundation. See plan task 4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Type the dict/set aggregation results (clarity for future maintainers) - Single early-return when no skills match (drops 4 repeated guards) - Defense-in-depth: catch EmbeddingNotConfigured at embed_text site - Fix test_empty_registry data leak: restore embeddings in finally Code review on 10ae26e. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…script - skills.py: embed on POST and on PATCH when name/description changes (body excluded) - backfill_embeddings.py: --batch-size, --dry-run, --only-missing/--all - docker-compose: run backfill after migrations, before uvicorn (fail-soft) - 9 integration tests cover happy + missing-key + body-only-change paths Embedding failures NEVER block skill CRUD — they log a warning and leave embedding NULL. Part of SkillNote x OpenClaw foundation. See plan task 4.5.
- Extract _refresh_embedding helper; replace 3 duplicated try/except sites - Helper also catches ValueError defensively (e.g., empty embedding text) - Add 10th test covering restore_version re-embed path Code review on 1c33d07. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
POST: validate task_summary length, skill_id existence, risk/outcome enums. Persists with stringified skill_ids for JSONB storage. GET: filter by skill_id (JSONB containment), since timestamp, before cursor. Default limit 50, max 200. Cursor format: '<iso>:<uuid>' for created_at + id tiebreak. 13 integration tests covering happy + each validation path. Part of SkillNote x OpenClaw foundation. See plan task 5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Test fixture registers generic_exception_handler for prod parity - test_get_returns_recent_events_default_50: tag events with unique agent_name + future timestamps so the assertion is independent of other suites' inserts - Move "Task 11 will hit this" note out of GET docstring to a # comment Code review on 256af95. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
POST: accept author_type/comment_type/rating/linked_usage_id; validate
linked_usage_id existence (404 LINKED_USAGE_NOT_FOUND); defense-in-depth
guard for agent-without-comment_type (422).
GET/PATCH: response_model=CommentOut returns the new fields automatically.
Backwards compatible: legacy {author, body} POST still works (author_type
defaults to "human", others to None).
9 integration tests covering legacy + agent + linked-usage paths.
Part of SkillNote x OpenClaw foundation. See plan task 6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ode assertion - New 10th test: PATCH with body + rating/comment_type/author_type must preserve the originals (CommentUpdate only declares body; Pydantic strips unknowns by default) - Inline comment in test 3 explaining only VALIDATION_ERROR is reachable today; AGENT_COMMENT_REQUIRES_TYPE kept for forward compat Code review on d70c496.
Wires the openclaw router into main.py (3 endpoints now reachable), bumps package.json 0.3.4 → 0.4.0, adds CHANGELOG entry calling out the embedding env requirement and the postgres image bump. Part of SkillNote × OpenClaw foundation. See plan task 7.
Always-injected meta-skill that teaches OpenClaw:
- What SkillNote is and where it lives
- When to consult (triggers + anti-triggers)
- How to spawn the resolver subagent
- How to log usage events (with hard rule: paraphrase, not raw msg)
- How to reflect via comments (5 comment_types, rate-limited)
- When to ask the user vs. act silently
- Where to send the user for review (only on demand)
- What NOT to do (marketplace install, raw msg logging, runtime config mutation)
Templated with {{HOST}} and {{WEB_URL}} placeholders for the install bash.
Stays under OpenClaw's 12K bootstrapMaxChars cap.
Also drops config.template.json with safe defaults (no auto marketplace
install, no draft creation since v2 has no drafts table).
Part of SkillNote x OpenClaw foundation. See plan task 8.
Subagent invoked by skillnote-awareness when the main agent needs to pick
skills for a task. Returns structured JSON only — never executes the task,
never installs skills, never edits files.
6 steps: read input, POST /v1/openclaw/context-bundle, score+pick, set
confidence/risk_level, decide on user confirmation, handle missing capability.
8 hard rules at the bottom.
Output schema matches the contract awareness skill expects (PRD §15).
Templated with {{HOST}} for the install bash. Marked subagent: true (not
always-injected).
Part of SkillNote × OpenClaw foundation. See plan task 9.
GET /v1/openclaw-bundle.zip — serves plugin-openclaw/ as a ZIP with
{{HOST}} and {{WEB_URL}} substituted from the request host. Mirrors the
Claude Code /v1/plugin.zip pattern.
GET /setup/openclaw — bash installer that downloads the bundle, refuses
symlink entries (defense-in-depth), and drops the 2 skills into
~/.openclaw/skills/ + config.json into ~/.openclaw/skillnote/.
Interactive consent prompt on TTY; non-interactive on CI.
8 integration tests covering bundle assembly, placeholder substitution,
bash syntax (bash -n), and config template inclusion.
Part of SkillNote x OpenClaw foundation. See plan task 10.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New section between "Skill Settings" and "About": - One-line install command with Copy button - Three-bullet "what gets installed" summary - Live status indicator: green/gray/yellow based on GET /v1/openclaw/usage?limit=1 (<=7d activity = connected) - Learn-more link to /docs/openclaw-integration Reads the API URL via the existing client helper; uses lucide-react icons + sonner toast on copy. Matches existing card aesthetics (same h2 styling, same text color tokens, no new design tokens). Part of SkillNote x OpenClaw foundation. See plan task 11.
User-facing guide covering install, what gets installed, what the agent does post-install, what the human does, settings/defaults, uninstall, troubleshooting (4 common scenarios). Linked from Settings → OpenClaw Integration → Learn more. Part of SkillNote × OpenClaw foundation. See plan task 12.
The OpenClaw resolver subagent runs in the agent harness with full LLM reasoning over the skill catalog. It does the relevance picking — SkillNote just ships the universe. We don't need server-side semantic ranking. Removed: - pgvector extension + skills.embedding column + HNSW index (migration 0016) - backend/app/services/embedding_service.py + tests - backend/scripts/backfill_embeddings.py + tests - 503 EMBEDDING_NOT_CONFIGURED / 502 EMBEDDING_PROVIDER_ERROR paths - pgvector, openai, numpy backend deps - pgvector/pgvector:pg16 image (back to postgres:16) - SKILLNOTE_EMBEDDING_API_KEY operator requirement - backfill step from docker-compose entrypoint Kept (still needed): - skill_usage_events table - comments extension (author_type, comment_type, rating, linked_usage_id) - All 4 openclaw endpoints (/context-bundle, /usage, /openclaw-bundle.zip, /setup/openclaw) - 2-skill bundle (skillnote-awareness, skillnote-resolver) - Settings → OpenClaw card context-bundle now returns up to max_skills sorted by usage_count_30d desc then rating_avg desc; the subagent re-ranks via LLM. Optional collection_filter narrows the catalog when the agent has a hint. Migration 0015 now guards its pgvector parts with a runtime check so a fresh DB on plain postgres:16 (no pgvector available) can still replay the migration sequence cleanly. Migration 0016 drops the column + index + extension via IF EXISTS for idempotency. Course correction on PR #29 architecture per asks.md DD5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GET /v1/openclaw-bundle.zip reads from _OPENCLAW_DIR which falls back
to Path("/openclaw") when present. The api container had no such mount,
so the bundle returned an empty ZIP and 4 setup tests failed.
Mirrors the existing ./plugin:/plugin:ro pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- openclaw.py: validate collection_id exists before INSERT to return 422 (UNKNOWN_COLLECTION_ID) instead of letting an FK violation 500 - openclaw.py: deduplicate skill_ids before storing to prevent each event from inflating usage_count_30d by the number of duplicates instead of 1 - comments.py: for agent comments with linked_usage_id, cross-check that the commented skill is actually in the event's skill_ids — prevents agents from corrupting skill ratings by cross-linking unrelated events (cross-check is skipped when event.skill_ids is empty) Also adds regression tests for all three fixes in test_openclaw_usage.py and test_comments_extension.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The analytics dashboard reads skill_call_events but OpenClaw logs to skill_usage_events — so the dashboard always showed zero. When an OpenClaw usage event is created, insert one skill_call_event per skill so the existing analytics page surfaces OpenClaw activity alongside Claude Code plugin usage without any frontend changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
completion_rate in /v1/analytics/top-skills was always 0 for OpenClaw because it reads skill_ratings but agents post ratings via comment.rating. When an agent comment with a non-null rating is created, also insert a skill_ratings row so the analytics completion_rate reflects OpenClaw feedback alongside Claude Code plugin ratings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tests Bug 5 (High): reject empty/whitespace comment bodies on POST and PATCH — CommentCreate and CommentUpdate now strip and validate body in a field_validator; previously body="" or " " silently stored junk. Bug 6 (Medium): block humans from spoofing agent_ comment_type namespace — model_validator in CommentCreate rejects comment_type starting with "agent_" when author_type=human; previously a human could forge agent_deprecation_warning and corrupt context-bundle staleness detection. Bug 7 (Medium): make days=0 consistently rejected across analytics endpoints — summary, skill-calls, agents, top-skills, rating-summary, and collections all changed from ge=0 to ge=1, matching timeline which already had ge=1; previously days=0 silently returned all-time data with no indication to the caller. Bug 1 (Medium): reject empty collection_filter in context-bundle request — added min_length=1 to ContextBundleRequest.collection_filter; previously "" bypassed the WHERE clause and returned all skills silently. Bug 3 (Medium): add deterministic ORDER BY to context-bundle candidate fetch — LIMIT max_skills*4 now has ORDER BY Skill.name so the candidate window is stable across calls; previously no ORDER BY meant high-usage skills beyond the window could be excluded non-deterministically. Regression tests: 14 new tests across test_comments_extension.py, test_openclaw_context_bundle.py, and new test_analytics_validation.py. All 58 affected tests pass (58/58). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
skillnote-awareness → skillnote (ClawhHub name): - ClawhHub-compatible frontmatter: always:true, emoji, version, requires.bins, companion_skills so `clawhub install skillnote` pulls both skills in one command - Full 5-step setup section: reads config.json → asks for SkillNote URL → tests connectivity → asks Y/n consent before grafting AGENTS.md → reports once then goes silent on all subsequent loads - Self-healing: re-grafts AGENTS.md marker silently if it disappears - Weekly self-update check via GET /v1/openclaw-skill + clawhub install - Clean uninstall path (removes AGENTS.md block + config + clawhub uninstall) - Complete operations manual: usage logging, reflection comments, activity API skillnote-resolver: add version + parent_skill metadata for ClawhHub linking backend/seed_data/skillnote.skill/: canonical seed for GET /v1/openclaw-skill (the endpoint the skill pings weekly to pull updates) Users can now install with: clawhub install skillnote No SkillNote CLI required. Skill guides its own setup on first load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
skillnote-awareness → skillnote (slug rename for ClawhHub keyword ranking): - Fix metadata: single-line JSON so `always: true` actually fires in OpenClaw - ClawhHub-optimized description (~240 chars, agent-centric, first-mover framing) - Remove skillnote.app default URL — self-hosted only, GitHub link for setup - Add references/ folder: api-reference.md + troubleshooting.md (on-demand load) - Step 4 cross-promotes skillnote-doctor on first setup skillnote-resolver: - Fix metadata: single-line JSON + emoji + parent_skill for ClawhHub linking - ClawhHub-optimized description (~243 chars) skillnote-doctor (NEW — viral wedge): - Targets "debug openclaw", "skills not loading", "why isn't X working" search intents - 6-check diagnostic: clawhub binary → config → reachability → AGENTS.md → resolver installed → resolver endpoint - When SkillNote absent: outputs install instructions → organic conversion funnel config.template.json moved inside skillnote/ (skill self-contained for clawhub install) backend/seed_data synced with plugin-openclaw/skillnote/SKILL.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The skillnote SKILL.md's weekly self-update check does:
GET {{HOST}}/v1/openclaw-skill
and compares the returned version against the installed VERSION file.
This endpoint was referenced in the skill but never implemented.
Returns {"version": "2.0.0", "skill": "<SKILL.md content>"} from
seed_data/skillnote.skill/ so installed agents can detect when a newer
version is published to ClawhHub.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- analytics/top-skills: replace mislabeled completion_rate (rating_count/call_count)
with real success_rate (outcome='completed'/total) via skill_usage_events LATERAL join
- analytics/ratings: NULL guard on avg_rating float conversion (float(None) crash)
- analytics/ratings/{slug}: .one() → .one_or_none() + 404 when no ratings exist
(was throwing 500 NoResultFound on unrated skills)
- analytics/ratings/{slug} versions loop: NULL guard on per-version avg_rating
- openclaw/context-bundle: NULL guard on recent_comments_summary body slicing
(row.body can be None; body[:200] raised TypeError)
- openclaw/openclaw-skill: replace raw JSONResponse with api_error() for consistent
error envelope; separate VERSION vs SKILL.md missing cases
- openclaw: add GET /v1/me/activity?period=7d — agent activity digest endpoint
referenced in SKILL.md but never implemented; returns invocations, top_skills,
agent_comments, window_start, window_end
Skill files (plugin-openclaw/skillnote/ + seed_data sync):
- Usage logging: clarify "one event per task not per skill", explicit "unknown"
outcome option, clearer payload example, explicit when-to-post rule
- Step 4 success message: remove broken {{HOST}}/me/activity UI path reference,
replace with natural-language instruction ("ask me what skills you've been using")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…reated_at in outcomes CTE - SkillListItem now exposes `id` (UUID) so agents can use it in usage logging - analytics top-skills: qualify `created_at` as `sue.created_at` in outcomes CTE to resolve ambiguity when LATERAL JOIN brings in skills.created_at Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ot uuid) Collection identifiers are collection name strings, not UUIDs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
comment_type was typed as str|None which accepted any string. Replaced with a Literal union (AgentCommentType) that constrains it to the five valid agent-reserved values, making Pydantic return a 422 VALIDATION_ERROR for any other input (closes Scenario 10 failure). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ssive model compliance The old block said "spawn skillnote-resolver" which models interpreted as optional. New block gives concrete exec steps with curl commands the model can copy-paste-execute, and removes the ambiguous "skip trivial tasks" exception that caused models to skip the check entirely. Tested: gpt-5.4 now calls context-bundle before every response and logs usage after — usage events logged for commit, review, and debug tasks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…er to write skills locally - context-bundle now returns content_md for each skill so agents can apply the actual skill body without a second API call - skillnote-resolver updated to download selected skills to ~/.openclaw/skills/sn-<slug>/ and return skill_paths so the main agent can read them natively - AGENTS.md graft template: explicit exec/curl steps with content_md awareness Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ngle skillnote skill Replace the two-skill architecture (skillnote + skillnote-resolver subagent) with a single, self-contained skillnote SKILL.md. The resolver's ranking logic is no longer needed: the AGENTS.md graft now embeds direct exec/curl instructions for context-bundle and usage logging, which GPT-5.4 follows reliably without subagent delegation. Syncs the simplified SKILL.md to backend/seed_data so seed scripts stay in sync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ntext-bundle calls
Replace the per-task context-bundle curl with a local sync model:
- Add sync.sh: fetches all skills from GET /v1/skills, writes sn-{slug}/SKILL.md to
~/.openclaw/skills/, handles create/update/delete via manifest, throttled at 60s
- Include skill UUID in frontmatter so agents can log usage without an extra API call
- AGENTS.md graft now runs sync.sh before each task, then reads relevant sn-* files
- Mirrors the Claude Code plugin's auto-sync.sh pattern (UserPromptSubmit-throttled)
Skills are always fresh on disk. No API calls during task execution.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… issues The previous version embedded $SKILLS directly in a Python heredoc which broke on skill content containing single quotes. Now writes to a tempfile and passes it as a CLI argument to the Python script. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sync.sh now runs two jobs:
- Skills sync (every 60s): fetch all skills → write sn-{slug}/SKILL.md
- Self-update (every 24h): GET /v1/openclaw-skill → compare VERSION →
auto-install via clawhub if newer, or overwrite SKILL.md directly as fallback
Users get skill package updates automatically within 24h of publishing,
no manual clawhub update required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nd test suite
Rating footer (sync.sh):
- Every synced sn-*/SKILL.md gets a pre-filled curl rating command appended
- Agent reads the skill and sees "rate it now (in this same turn)" with the
exact curl command — no cross-session memory needed
Log-watcher (log-watcher.py):
- Watches ~/.openclaw/agents/main/sessions/*.jsonl for toolCall{read} events
- Detects reads of sn-*/SKILL.md → POST /v1/hooks/skill-used automatically
- inode + byte offset tracking (handles rotation, no double-counting)
- Per-session deduplication, partial-line safety, no external dependencies
- PID-guarded daemon launched by sync.sh, 2s poll loop
Tests (28/28 passing):
- test_log_watcher.py: process_file, find_session_files, post_skill_used
- test_sync_footer.py: footer content, host/slug injection, JSON validity
- test_e2e.sh: live server E2E (footer + analytics increment)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Rework the SkillNote × OpenClaw install so the user types one prompt
("install skillnote from clawhub") and the agent handles everything
— including standing up the SkillNote backend if missing, syncing
skills, and grafting AGENTS.md.
Backend (FastAPI):
- GET /setup/agent — unified curl entry point with --agent <name>
flag (claude-code | openclaw); delegates to the per-agent installer
via tempfile (avoids curl|bash < /dev/null truncation)
- GET /setup/agent-prompt?agent=... — returns a personalized
api2cli-style copy-prompt with the user's host pre-baked
- Rewrote /setup/openclaw installer: unified single skillnote skill
(drops legacy 2-skill bundle), preserves existing config.json on
re-install, kicks off first sync, runs chmod +x sync.sh
- Fixed /v1/openclaw-skill: _SKILL_DIR now points at /openclaw mount
(was pointing at non-existent seed_data/ in container)
Skill bundle (plugin-openclaw/skillnote/):
- install-backend.sh (new) — clones repo + runs ./install.sh + polls
/health; ships in clawhub bundle so the agent has it on disk and
doesn't need curl|GitHub-raw at install time
- SKILL.md frontmatter is now clawhub-native: always: true,
primaryEnv: SKILLNOTE_BASE_URL, requires.env, envVars schema,
homepage field
- SKILL.md Step 1: layered host resolution (env → file → default
localhost:8082) with reach test
- SKILL.md Step 2: when localhost unreachable, agent runs
install-backend.sh itself (with consent) — no manual clone required
- SKILL.md Step 5: AGENTS.md graft moved out of the agent (which
fights consent prompts) and into sync.sh; Step 5 now just verifies
- sync.sh: appends <skillnote v1> block to AGENTS.md idempotently;
honors {"grafted": false} opt-out flag
- sync.sh: mkdir-based single-writer lock + atomic manifest write
(tempfile + os.replace) to prevent concurrent-sync corruption
Web UI (src/app/(app)/integrations/page.tsx):
- "Copy prompt" is now the primary tab on the OpenClaw section
(matches api2cli-style ecosystem convention); fetches the
personalized prompt from /setup/agent-prompt with user's URL baked in
- clawhub tab shows two-stage clone+./install.sh + clawhub install
block (makes registry prereq explicit)
- curl tab uses unified /setup/agent --agent flag
- Manual tab simplified to 4 steps
- Both Claude Code and OpenClaw cards have live connection status pills
install.sh:
- Footer detects which agents are present on the host (~/.claude,
~/.openclaw) and shows the matching curl --agent ... command
- Clear "Stage 1 complete → Stage 2 next" framing; no auto-wire of
Stage 2 (avoids wrong-machine / wrong-URL / wrong-user-id footguns)
- Points at /integrations for the web UI walkthrough
Docs:
- docs/openclaw-hld.md (new) — HLD covering user journey, component
map, three loops, three feedback channels, install architecture,
and failure modes
- README.md updated with new install method order (Copy prompt
recommended) and unified curl endpoint
Verified end-to-end against a real OpenClaw agent on a remote Mac mini:
mom-user vague prompts, pro-user terse prompts, idempotent re-install,
opt-out, recovery (install-backend.sh missing → GitHub raw fallback),
real skill use → analytics roundtrip → agent-posted ratings reaching
skill_ratings table.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updates the HLD doc to reflect the architectural shift made during E2E testing: the AGENTS.md graft happens shell-side in sync.sh, not via the agent's file-edit tool. - §1 user journey: Step 4 now notes sync.sh grafts AGENTS.md; Step 5 reduced to verification (no consent prompt) - "Total user input" updated: at most 1 Y/n (backend install consent only) - §5 design choices table: added entry explaining why graft moved out of the LLM into sync.sh - §8 install architecture: new "consent-prompt anti-pattern" section documenting the LLM safety-training failure mode (LLM kept asking even with explicit "do NOT ask" instructions in SKILL.md), the fix (move graft to shell), and the general principle: any time you'd write "agent should not ask consent" in a SKILL.md, that's a signal to move the action into a shell script Verified end-to-end on remote OpenClaw agent: terse "set up skillnote" prompt now completes the full install with no consent prompt and graft in place. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the foundational layer for SkillNote × OpenClaw — the OpenClaw agent gets a semantically-ranked skill registry it can autonomously consult, log usage against, and reflect on. Three new endpoints under
/v1/openclaw/, one new table, comments extended for agent reflections, pgvector-backed semantic ranking, a 2-skill bundle delivered via bash installer, and a Settings → OpenClaw card.This PR covers PRD Milestones 1+2 (Foundation + Resolver Contract). UI surfaces (Activity feed, Skill Garden, Agent Suggestions) and persistence for drafts/marketplace candidates are scoped to v0.4.1.
What's in this PR
Backend
0015_openclaw_foundation— pgvector extension +skills.embedding vector(1536)+ HNSW cosine index +skill_usage_eventstable + comments extension (author_type/comment_type/rating/linked_usage_id).POST /v1/openclaw/context-bundle— pgvector cosine-ranked skill bundle for the resolver subagent. NULL embeddings excluded (forces backfill).POST/GET /v1/openclaw/usage— agents log usage events; pagination via?beforecursor +?since/?skill_idfilters.author_type=agent,comment_type,rating,linked_usage_id); validates linked_usage_id existence; backwards-compatible with legacy{author, body}POSTs.backend/app/services/embedding_service.py) — pluggable provider (OpenAI default, Voyage supported), LRU cache, dimension guard. Embedding failure NEVER blocks skill CRUD.|| true).OpenClaw bundle
plugin-openclaw/skillnote-awareness/SKILL.md— always-injected meta-skill that teaches the main agent when/how to consult SkillNote, log usage, leave reflections, and when to ask the user vs. act silently.plugin-openclaw/skillnote-resolver/SKILL.md— focused subagent that returns structured JSON only (PRD §15 contract).plugin-openclaw/config.template.json— defaults: auto-resolve ON, write-reflections ON, marketplace-install OFF, draft-creation OFF.Install path
GET /v1/openclaw-bundle.zip— bundle ZIP with{{HOST}}and{{WEB_URL}}substituted from request host. Refuses symlink entries.GET /setup/openclaw— bash installer with TTY consent prompt. Drops 2 skills into~/.openclaw/skills/and config into~/.openclaw/skillnote/.Frontend
GET /v1/openclaw/usage?limit=1, ≤7d activity = green), and Learn-more link.Docs + release
docs/openclaw-integration.md— install, what gets installed, what the agent does, what the human does, settings, uninstall, troubleshooting.docker-compose.ymlpostgres image bumped topgvector/pgvector:pg16.What's NOT in this PR
Deferred to v0.4.1:
skill_draftsandmarketplace_candidatestables.cli/) was confirmed orphaned (no references from install.sh, package.json workspaces, .github, Dockerfiles, or plugin); whole-CLI deprecation is a separate follow-up PR, not bundled here.Set
SKILLNOTE_EMBEDDING_API_KEYbefore upgrading. Without it,POST /v1/openclaw/context-bundlereturns 503EMBEDDING_NOT_CONFIGURED. Skill CRUD continues to work (embeddings stay NULL until a key is set + backfill runs).Optional env vars:
SKILLNOTE_EMBEDDING_PROVIDER=openai|voyage(default openai)SKILLNOTE_EMBEDDING_MODEL=text-embedding-3-small(default)The api container's entrypoint runs
backfill_embeddings.py --only-missingafter migrations so existing skills get embeddings on first start with the key set.Migration safety
0015_openclaw_foundationadds nullable columns + new table + pgvector extension. Safe under concurrent writes.comments.author_typeadded NOT NULL withserver_default='human'for safe backfill, then server_default dropped.gen_random_uuid()server-side default onskill_usage_events.id(Postgres 13+ built-in, no pgcrypto needed).Test plan
Backend integration:
/v1/openclaw/context-bundle(semantic ranking, NULL-embedding exclusion, staleness rules, N+1 sentinel ≤6 queries, error envelopes)./v1/openclaw/usage(POST validation, JSONB containment filter, cursor pagination)./setup/openclaw+ bundle ZIP (placeholder substitution, bash syntax check).Backend unit:
Smoke test (full stack):
setup/openclawscript passesbash -nsyntax check.Total backend tests added: 61 (52 integration + 9 unit). All passing.
Spec sources
skillnote_openclaw_living_skill_system_prd.mddocs/superpowers/plans/2026-04-26-skillnote-openclaw-asks.mddocs/superpowers/plans/2026-04-26-skillnote-openclaw-v2.md🤖 Generated with Claude Code