Skip to content

feat: skills framework, context protocol, HTTP API, and agent-aware handoff#52

Merged
JordanCoin merged 6 commits intomainfrom
feat/skills-and-context
Mar 25, 2026
Merged

feat: skills framework, context protocol, HTTP API, and agent-aware handoff#52
JordanCoin merged 6 commits intomainfrom
feat/skills-and-context

Conversation

@JordanCoin
Copy link
Copy Markdown
Owner

Summary

Phases 2 & 3 of codemap's evolution into a code-aware AI coding system. Builds on #49 (merged).

Phase 2: Skills Framework

  • skills/ package — YAML frontmatter parser, multi-source loader (builtin → project → global), weighted matching
  • 5 builtin skills embedded in binary: hub-safety, refactor, test-first, explore, handoff
  • codemap skill list|show|init CLI
  • list_skills / get_skill MCP tools
  • Hook integration — prompt-submit matches and injects relevant skills automatically

Phase 3: Context Protocol & HTTP API

  • codemap context — universal JSON envelope for any AI tool (--for, --compact)
  • codemap serve --port 9471 — REST API: /api/context, /api/skills, /api/working-set, /api/health
  • Agent-aware handoffAgentEntry records which agent worked, auto-detects Claude/Codex/Cursor

README updated

  • Skills section with builtin list and custom skill guide
  • Intelligent routing section explaining intent classification
  • Updated roadmap

Test plan

  • go test ./... -race — all 10 packages pass
  • codemap skill list — shows 5 builtins
  • codemap context --for "refactor auth" — returns full envelope
  • codemap serve — all 6 endpoints verified with curl
  • Irrelevant prompts inject zero skills (priority fix from codex review)
  • Codex reviewed Phase 2: 3 findings, all fixed

🤖 Generated with Claude Code

JordanCoin and others added 3 commits March 24, 2026 23:26
…ools

Phase 2 of codemap's evolution. Skills are markdown files with YAML frontmatter
that provide context-aware guidance to AI agents. They're matched against the
user's intent, mentioned files, and detected languages.

New package: skills/
- types.go — SkillMeta, Skill, SkillIndex with fast lookup by name/keyword/language
- loader.go — Multi-source loading (builtin → project → global), YAML frontmatter
  parsing, deduplication (later sources override), weighted matching
- embed.go — go:embed for builtin skills
- 5 builtin skills: hub-safety, refactor, test-first, explore, handoff

New: cmd/skill.go — CLI subcommand (list, show, init)
New: MCP tools — list_skills (metadata only) and get_skill (full body)

Hook integration:
- hookPromptSubmit matches skills against intent + files + languages
- Top 3 skills injected with <!-- codemap:skills --> structured marker
- Budget-capped at 8KB to prevent context blowup

Bug fixes from parallel reviews:
- [P1] Priority boost only applies after real signal (codex finding)
- [P2] Fallback name derived from filename for frontmatter-less skills
- [P1] showSessionProgress now counts unique hub files, not hub events
  (Claude code-reviewer finding from Phase 1 worktree review)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…oadmap

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Phase 3 of codemap's evolution into a code-aware AI coding system.

New: codemap context
- Universal JSON envelope any AI tool can consume
- --for "prompt" pre-classifies intent with matched skills
- --compact mode for token-constrained agents
- Includes project info, intent, working set, skills, handoff ref

New: codemap serve --port 9471
- GET /api/context?intent=refactor+auth&compact=true
- GET /api/skills?language=go&category=refactor
- GET /api/skills/<name>
- GET /api/working-set
- GET /api/health
- Uses net/http stdlib, no new dependencies

New: Agent-aware handoff history
- AgentEntry type records agent ID, timestamps, files edited
- Session-stop auto-detects agent (Claude Code, Codex, Cursor)
- History carried across sessions, capped at 20 entries
- Enables true multi-agent continuity

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 25, 2026 03:27
- Bind HTTP server to 127.0.0.1 by default (security: P1)
- Add --host flag for explicit network bind control
- Add server timeouts (ReadHeader, Read, Write, Idle)
- Remove absRoot from /api/health response
- Use flag.ContinueOnError for controlled error handling
- Sort Languages output for deterministic JSON
- Detect languages from imports + hubs, not just importers
- Fix comment: Cursor detection uses CURSOR_SESSION_ID

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Phase 2/3 building blocks for codemap’s evolution into an agent-integrated system by introducing a skills framework, a standard “context envelope” protocol, and new integration surfaces (MCP + HTTP), plus agent-aware handoff history.

Changes:

  • Introduces skills/ package with frontmatter parsing, builtin embedding, multi-source loading, and intent/file/language matching (+ tests and builtin skill docs).
  • Adds new CLI subcommands: codemap skill ..., codemap context ..., and codemap serve ... (HTTP API endpoints).
  • Extends MCP server with list_skills / get_skill tools; extends handoff artifacts with agent session history and updates hooks to inject matched skills.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
skills/types.go Defines skill metadata, skill model, and index structures.
skills/loader.go Implements skill loading (builtin/project/global), frontmatter parsing, and matching.
skills/embed.go Embeds builtin skills into the binary and loads them at runtime.
skills/loader_test.go Adds tests for parsing, loading, indexing, and matching behavior.
skills/builtin/hub-safety.md Adds builtin “hub-safety” guidance content.
skills/builtin/refactor.md Adds builtin “refactor” guidance content.
skills/builtin/test-first.md Adds builtin “test-first” guidance content.
skills/builtin/explore.md Adds builtin “explore” guidance content.
skills/builtin/handoff.md Adds builtin “handoff” guidance content.
cmd/skill.go Adds `codemap skill list
cmd/context.go Adds codemap context JSON envelope generator.
cmd/serve.go Adds codemap serve HTTP API endpoints for context/skills/working-set/health.
cmd/hooks.go Injects matched skills into prompt-submit output; records agent session history in handoff; adjusts hub edit counting.
cmd/hooks_test.go Updates session-progress test expectation for unique hub files counting.
mcp/main.go Adds MCP tools to list skills and fetch skill bodies.
handoff/types.go Adds AgentEntry and AgentHistory to persisted handoff artifact.
main.go Routes new subcommands before global flag parsing.
go.mod Adds YAML dependency for frontmatter parsing.
README.md Documents skills framework and updates command list/roadmap.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +794 to +802
body := m.Skill.Body
if totalBytes+len(body) > maxSkillOutputBytes {
remaining := maxSkillOutputBytes - totalBytes
if remaining > 100 {
body = body[:remaining] + "\n... (skill truncated)"
} else {
break
}
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

body = body[:remaining] truncates by bytes and can split a UTF-8 rune, producing invalid text output. If these skill files may contain non-ASCII, consider truncating at a rune boundary (e.g., via utf8.ValidString check / rune iteration) before printing.

Copilot uses AI. Check for mistakes.
Comment on lines +208 to +219
// Detect languages from all known files (importers + imports + working set)
langSet := make(map[string]bool)
if info != nil {
for file := range info.Importers {
if lang := scanner.DetectLanguage(file); lang != "" {
langSet[lang] = true
}
}
for file := range info.Imports {
if lang := scanner.DetectLanguage(file); lang != "" {
langSet[lang] = true
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx.Languages is built by iterating over a map, so the output order is nondeterministic across runs. If the context envelope is meant to be stable/cachable/diff-friendly, sort ctx.Languages (and potentially TopHubs) before returning.

Copilot uses AI. Check for mistakes.
Comment on lines +127 to +138

addr := fmt.Sprintf("%s:%d", *host, *port)
fmt.Printf("codemap serve — listening on http://%s\n", addr)
fmt.Printf(" GET /api/context?intent=refactor+auth&compact=true\n")
fmt.Printf(" GET /api/skills?language=go&category=refactor\n")
fmt.Printf(" GET /api/skills/<name>\n")
fmt.Printf(" GET /api/working-set\n")
fmt.Printf(" GET /api/health\n")
fmt.Println()

server := &http.Server{
Addr: addr,
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This server binds to all network interfaces by default (":<port>"). Since these endpoints expose local repo paths and other potentially sensitive project context, consider binding to localhost by default (e.g., "127.0.0.1") and/or adding an explicit --bind flag to opt into external exposure.

Copilot uses AI. Check for mistakes.
Comment on lines +106 to +110
func buildContextEnvelope(root, prompt string, compact bool) ContextEnvelope {
projCfg := config.Load(root)
info := getHubInfoNoFallback(root)

envelope := ContextEnvelope{
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildContextEnvelope is a new protocol surface with multiple branches (compact vs full, prompt vs no prompt, skills/working-set/handoff). There are no unit tests covering these cases yet; adding focused tests would help prevent regressions as the protocol evolves.

Copilot uses AI. Check for mistakes.
Comment on lines +795 to +807
if totalBytes+len(body) > maxSkillOutputBytes {
remaining := maxSkillOutputBytes - totalBytes
if remaining > 100 {
body = body[:remaining] + "\n... (skill truncated)"
} else {
break
}
}

fmt.Println()
fmt.Printf("📘 Skill: %s\n", m.Skill.Meta.Name)
fmt.Println(body)
totalBytes += len(body)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The truncation logic can exceed maxSkillOutputBytes because it slices to remaining and then appends the "... (skill truncated)" suffix without accounting for the suffix bytes. This defeats the intended output budget cap; consider reserving space for the suffix (or updating totalBytes based on the pre-suffix remaining) so the printed content never exceeds the cap.

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +96
func runSkillInit(root string) {
skillsDir := root + "/.codemap/skills"
if err := os.MkdirAll(skillsDir, 0755); err != nil {
fmt.Fprintf(os.Stderr, "Error creating skills directory: %v\n", err)
os.Exit(1)
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Path construction uses string concatenation (root + "/.codemap/skills"), which is not portable on Windows and can introduce double slashes. Prefer filepath.Join(root, ".codemap", "skills") here to match other cmd code.

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +122
path := skillsDir + "/my-skill.md"
if _, err := os.Stat(path); err == nil {
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly, path := skillsDir + "/my-skill.md" should use filepath.Join for cross-platform correctness and to avoid edge cases with trailing slashes in root.

Copilot uses AI. Check for mistakes.
Comment on lines +223 to +229
// matchPath does a simple glob-like match: supports * and ** patterns,
// and falls back to substring matching.
func matchPath(pattern, path string) bool {
// Simple substring match for non-glob patterns
if !strings.ContainsAny(pattern, "*?") {
return strings.Contains(path, pattern)
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says this supports ** patterns, but the implementation uses filepath.Match, which does not treat ** specially. Either implement ** support (e.g., via a doublestar-style matcher) or update the comment so callers don’t assume recursive globbing works.

Copilot uses AI. Check for mistakes.
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.3.8 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gopkg.in/yaml.v3 is imported directly (skills/loader.go), so it should be a direct dependency in go.mod (remove the // indirect comment). Running go mod tidy should fix this.

Suggested change
gopkg.in/yaml.v3 v3.0.1 // indirect
gopkg.in/yaml.v3 v3.0.1

Copilot uses AI. Check for mistakes.
Comment on lines +1018 to +1019
if !strings.Contains(out, "1 hub edits") {
t.Errorf("expected '1 hub edits' (unique hub files, not events), got %q", out)
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expected output string uses incorrect pluralization ("1 hub edits"). Consider updating the production output to handle singular vs plural (e.g., "1 hub edit") and adjust this assertion accordingly.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d9fdde7e14

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

cmd/serve.go Outdated
writeJSON(w, map[string]string{"status": "ok", "root": absRoot})
})

addr := fmt.Sprintf(":%d", *port)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Bind the HTTP server to loopback by default

Using addr := fmt.Sprintf(":%d", *port) makes ListenAndServe bind on all interfaces, so codemap serve is reachable from the local network even though the log message implies localhost-only access. In environments where this runs on shared hosts, the API can expose repository metadata and handoff context to other machines; defaulting to 127.0.0.1 (or requiring an explicit bind address flag) avoids this unintended exposure.

Useful? React with 👍 / 👎.

Comment on lines +231 to +235
matched, _ := filepath.Match(pattern, path)
if matched {
return true
}
// Also try matching against just the filename
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Implement actual ** handling in path pattern matching

matchPath documents support for * and **, but it relies on filepath.Match, which does not implement recursive ** semantics. Any skill using patterns like src/**/handlers/*.go will never match and therefore won't activate, which breaks custom skill routing for nested paths.

Useful? React with 👍 / 👎.

JordanCoin and others added 2 commits March 24, 2026 23:34
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JordanCoin JordanCoin merged commit 26bbd39 into main Mar 25, 2026
12 checks passed
@JordanCoin JordanCoin deleted the feat/skills-and-context branch March 25, 2026 03:39
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.

2 participants