Skip to content

feat: SkillNote × OpenClaw foundation (v0.4.0)#29

Open
latentloop07 wants to merge 46 commits intomasterfrom
feat/openclaw-foundation
Open

feat: SkillNote × OpenClaw foundation (v0.4.0)#29
latentloop07 wants to merge 46 commits intomasterfrom
feat/openclaw-foundation

Conversation

@latentloop07
Copy link
Copy Markdown
Contributor

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

  • Migration 0015_openclaw_foundation — pgvector extension + skills.embedding vector(1536) + HNSW cosine index + skill_usage_events table + 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 ?before cursor + ?since/?skill_id filters.
  • Comments endpoint accepts agent fields (author_type=agent, comment_type, rating, linked_usage_id); validates linked_usage_id existence; backwards-compatible with legacy {author, body} POSTs.
  • Embedding service (backend/app/services/embedding_service.py) — pluggable provider (OpenAI default, Voyage supported), LRU cache, dimension guard. Embedding failure NEVER blocks skill CRUD.
  • Auto-embed on skill create/update/restore (only when name or description changes; body excluded). Backfill script wired into Docker entrypoint (fail-soft via || 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

  • Settings → OpenClaw card with copy-install-command button, three-bullet "what gets installed" summary, live "Connected" status indicator (hits 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.
  • Version bump 0.3.4 → 0.4.0 with full CHANGELOG entry.
  • docker-compose.yml postgres image bumped to pgvector/pgvector:pg16.

What's NOT in this PR

Deferred to v0.4.1:

  • Activity feed / Agent Suggestions / Skill Garden UI surfaces.
  • skill_drafts and marketplace_candidates tables.
  • LLM-assisted staleness detection (v0.4.0 uses rule-based: deprecated comment OR rating<3.0 → needs_review).
  • Multi-agent support (assumes single OpenClaw install per machine).
  • CLI tree (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.

⚠️ Operator action required

Set SKILLNOTE_EMBEDDING_API_KEY before upgrading. Without it, POST /v1/openclaw/context-bundle returns 503 EMBEDDING_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-missing after migrations so existing skills get embeddings on first start with the key set.

Migration safety

  • 0015_openclaw_foundation adds nullable columns + new table + pgvector extension. Safe under concurrent writes.
  • comments.author_type added NOT NULL with server_default='human' for safe backfill, then server_default dropped.
  • Downgrade tested clean (drop FK → drop comments cols → drop usage indexes → drop usage table → drop HNSW index → drop embedding column → drop vector extension).
  • pgvector gen_random_uuid() server-side default on skill_usage_events.id (Postgres 13+ built-in, no pgcrypto needed).

Test plan

Backend integration:

  • 11 tests for /v1/openclaw/context-bundle (semantic ranking, NULL-embedding exclusion, staleness rules, N+1 sentinel ≤6 queries, error envelopes).
  • 13 tests for /v1/openclaw/usage (POST validation, JSONB containment filter, cursor pagination).
  • 8 tests for /setup/openclaw + bundle ZIP (placeholder substitution, bash syntax check).
  • 10 tests for embedding wiring + backfill (only-missing, dry-run, restore re-embed, body-only-change skip).
  • 10 tests for comments extension (legacy compat, agent fields, linked_usage_id existence, PATCH ignores extra fields).

Backend unit:

  • 9 tests for embedding service (provider dispatch, LRU cache, dimension guard).

Smoke test (full stack):

  • All 4 openclaw endpoints respond correctly (incl. 503/422/201 paths).
  • Bundle ZIP serves 3 entries with placeholders substituted.
  • setup/openclaw script passes bash -n syntax check.
  • Settings page renders client-side; OpenClaw card present in JS bundle.
  • TypeScript type check passes.
  • Negative paths verified: task_summary > 1000 chars → 422, agent comment without comment_type → 422.

Total backend tests added: 61 (52 integration + 9 unit). All passing.

Spec sources

  • PRD: skillnote_openclaw_living_skill_system_prd.md
  • User direction + locked decisions: docs/superpowers/plans/2026-04-26-skillnote-openclaw-asks.md
  • Implementation plan: docs/superpowers/plans/2026-04-26-skillnote-openclaw-v2.md

🤖 Generated with Claude Code

latentloop07 and others added 30 commits April 26, 2026 23:59
…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>
latentloop07 and others added 16 commits April 27, 2026 23:52
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant