codemark
GitHub提供结构化代码书签管理功能,利用 tree-sitter AST 实现跨重构的持久化定位。支持语义搜索、标签过滤及上下文恢复,帮助 Agent 在会话中记忆关键代码位置并自动加载历史上下文。
Trigger Scenarios
Install
npx skills add DanielCardonaRojas/codemark --skill codemark -g -y
SKILL.md
Frontmatter
{
"name": "codemark",
"description": "Manage structural code bookmarks that survive refactoring. Use when the user says \"remember this\", \"bookmark this\", \"save this location\", \"load my bookmarks\", \"what do I have bookmarked\", \"mark this code\", \"codemark\", or when starting a new session and needing to reload context from a previous session. Also use proactively when you discover critical code during exploration — entry points, boundaries, configuration, error handling — that you'd want to remember if starting over.\n",
"allowed-tools": "Bash(codemark *)"
}
Codemark — Structural Code Bookmarking
You have access to codemark, a CLI tool that creates structural bookmarks for code using tree-sitter AST queries. Unlike file:line references, these bookmarks survive renames, refactors, and reformatting.
Active Context
When starting a session, inject a summary of active bookmarks:
codemark list --health active
Agent Directives: Handling Invocations
If the user invoked you with arguments (e.g. /codemark something), use $ARGUMENTS to search the active bookmarks or execute the desired behavior:
- Search text:
codemark search "$ARGUMENTS" - If it looks like a bookmark ID or UUID prefix:
codemark show "$ARGUMENTS" - If user asks to "open", "edit", or view a bookmark:
codemark open "$ARGUMENTS" - If no arguments were provided, interpret the user's intent based on the conversation context.
Author Identity (REQUIRED)
Whenever you create or annotate a bookmark, identify yourself by name with
--created-by. Do not use the generic agent value — be specific about which
agent you are. Use the slug that matches your own runtime:
| Agent | --created-by value |
|---|---|
| Claude / Claude Code | claude |
| OpenAI Codex | codex |
| GitHub Copilot | copilot |
| Pi | pi |
Reserve the default user for bookmarks the human creates themselves. The
examples below use --created-by claude; substitute your own agent slug from
the table above. This lets --author claude, --author codex, etc. filter
bookmarks by the specific agent that authored them.
Intelligent Bookmark Discovery
When the user asks about something, try these strategies in order:
1. Semantic Search (Most Flexible)
Best for natural language queries and conceptual searches:
codemark search "user query" --semantic
2. Tag-Based Filtering
When the user mentions specific concepts or categories. --tag on list is single-valued — pass one tag and combine it with other filters (--health, --author, --lang, --file). To narrow by multiple tags at once, use semantic search instead.
codemark list --tag feature:auth --health active
codemark list --tag layer:api --author claude
codemark list --tag type:config --lang rust
3. File-Aware Search
When discussing specific files or modules:
codemark list --file src/auth.rs --health active
codemark list --file src/auth.rs --lang rust
4. Collection Browsing (best for gathering context)
When exploring a feature or workflow, render the whole collection as markdown — this is the fastest way to load context: it includes the description, tags, links (PRs/docs), and every step's bookmark ID + note.
codemark tour list
codemark tour show <collection-name> --format markdown
Then drill into any step by its short ID: codemark show <id> --format markdown.
5. Hybrid Search Pattern
For best results, combine semantic search with filters. Note: search has no --tag flag — filter searches with --lang, --author, --health, --collection:
codemark search "authentication" --lang rust --author claude
codemark search "middleware" --health active --collection auth-flow
Discovery Strategy Summary
| User Query Type | Primary Strategy | Fallback |
|---|---|---|
| "Show my auth bookmarks" | --tag feature:auth |
semantic search |
| "Where's the config?" | --tag type:config |
--tag role:config |
| "Bookmarks in auth.rs" | --file src/auth.rs |
semantic search |
| "Bookmarks a specific agent authored" | --author <agent-slug> (e.g. --author claude) |
semantic search |
| "What did I mark for X?" | semantic search | tour browse |
When to use codemark
- Starting a session: Load bookmarks from a previous session to restore context.
- Exploring code: When you discover something critical, bookmark it with context about why it matters.
- During work: Bookmark code you'll need to reference later — especially cross-file relationships.
- Ending a session: Validate bookmarks so the next session has accurate references.
- Checking impact: Use
codemark tour diffto see which bookmarks are affected by recent changes.
Proactive bookmarking: When you recognize code that is critical to the current task — entry points, auth boundaries, error handling paths, configuration — bookmark it immediately with a note explaining its significance and relationship to the work. Don't bookmark everything you read; bookmark what you'd want to know if starting over tomorrow.
Key Concepts
- Bookmarks store a tree-sitter query that identifies code by AST structure, not line numbers.
- Resolution re-finds bookmarked code even after edits (exact → relaxed → hash fallback).
- Tours/Collections group related bookmarks (one per feature, bugfix, or investigation). Each carries a prompt — the polished restatement of the request that motivated it, so the tour can be recreated if its bookmarks drift beyond repair. See Recording the Prompt.
- Health: active (healthy), drifted (found but moved), stale (lost), archived (cleaned up).
- Author: bookmarks track who created them. Set
--created-byto your specific agent slug (claude,codex,copilot,pi) — not the genericagent; the defaultuseris reserved for the human. See Author Identity above. - Notes vs. Comments (two distinct, durable-vs-ephemeral channels):
- Notes (
--note) — durable explanations of what the code is and why it matters. Context-independent, reusable across any session. Use multiple--noteflags to capture different aspects. Rendered as plain prose (keep them clean and self-contained). - Comments (
--comment) — markdown discussion tied to a task, ticket, PR, or debugging session. Ephemeral and session-scoped. Rendered as markdown, so they may contain links, lists, and code blocks. Use these for "investigating X for TICKET-42" rather than polluting notes.
- Notes (
- Annotations: each
--note/--contextbecomes an annotation with provenance (author, timestamp, source), so multiple agents can layer context over time.
Recording the Prompt (collections)
Every collection you create should record the request that motivated it via
--prompt. This is the collection's seed of intent: if its bookmarks later drift
beyond repair, the prompt is what lets a future agent rebuild an equivalent tour
from scratch rather than guessing from the wreckage.
Write a polished restatement, not a transcript. Real prompts arrive rushed — typos, missing words, broken grammar, non-native English, stream-of-consciousness. Your job is to capture the idea in clean, well-formed English:
- Fix spelling, grammar, and punctuation; expand obvious abbreviations.
- Keep the user's actual intent and scope — don't add goals they never asked for, and don't narrow what they wanted.
- Preserve concrete specifics they supplied (file names, symbols, tickets, repos).
- Write it standalone: it must make sense with no conversation context. Resolve "this", "that file", "here" into real names.
- One to three sentences, imperative or declarative. No preamble like "The user asked me to".
- Keep technical terms the user used, even if informal — don't over-formalize into jargon they didn't use.
| User's raw prompt | --prompt value to record |
|---|---|
can u rember where the the auth stuf is i keep loosing it |
Bookmark the authentication code so it can be found again quickly. |
bookmark this (while viewing src/db/pool.rs) |
Bookmark the connection pool setup in src/db/pool.rs. |
i need to understan how a req goes from the api to the db for ENG-42 |
Trace how a request flows from the API layer down to the database, for ENG-42. |
mark all the places we validate input, theres like 5 of them i think |
Bookmark every input-validation site in the codebase. |
Do not paste the user's text verbatim when it contains errors, and do not
invent a prompt when you created the collection on your own initiative — in that
case state your own reason plainly: --prompt "Bookmark the error-handling boundaries discovered while debugging the retry loop."
If the user's request genuinely changes scope mid-session, replace the prompt rather than letting it go stale:
codemark tour annotate <name> --prompt "<updated polished intent>"
Omitting --prompt leaves any existing prompt untouched. An empty string is
rejected — to remove a prompt entirely, say so explicitly:
codemark tour annotate <name> --clear-prompt
The prompt is distinct from the description:
--prompt— why this collection was asked for (the request/intent).--description— what this collection contains (a summary of the tour).
Tag Taxonomy
Use structured, colon-prefixed tags for powerful filtering. Combine multiple tags to create precise filters.
Feature/Domain Tags
Identify which feature or domain area the bookmark belongs to.
feature:<name>— e.g.,feature:auth,feature:logging,feature:paymentsdomain:<name>— e.g.,domain:user-management,domain:analytics
Architectural Layer Tags
Identify the architectural layer or component boundary.
layer:api— HTTP handlers, API endpoints, controllerslayer:business— Business logic, domain services, use caseslayer:data— Database queries, repositories, data accesslayer:infra— Infrastructure, external services, I/Olayer:ui— UI components, views, presentation logiclayer:config— Configuration, constants, environment setup
Role/Responsibility Tags
Identify the primary role or responsibility of the code.
role:entrypoint— Application entry points, main functionsrole:handler— Request handlers, event handlersrole:service— Service layer, business logicrole:repository— Data access, database operationsrole:middleware— Middleware, interceptors, filtersrole:validator— Validation, verification logicrole:transformer— Data transformation, mapping, conversionrole:config— Configuration loading/parsingrole:constant— Constants, enums, static valuesrole:error— Error handling, error typesrole:test— Test utilities, fixtures, test helpersrole:utility— Helper functions, utilities
Type Tags
Identify the kind of code element.
type:function— Functions, methodstype:class— Classes, structstype:interface— Interfaces, protocols, traitstype:enum— Enums, unionstype:constant— Constants, literalstype:module— Modules, packages
Task/Work Tags
Link bookmarks to specific tasks or work items.
task:<id>— e.g.,task:fix-123,task:refactor-authpr:<number>— Associated pull requestissue:<number>— Associated issue
Security Tags
Identify security-sensitive code.
security:auth— Authentication, authorizationsecurity:crypto— Encryption, hashing, cryptographysecurity:validation— Input validation, sanitizationsecurity:sensitive— Accesses sensitive data
Recommended Tag Combinations
Apply multiple tags when creating a bookmark (add/edit/annotate accept repeated --tag). Note that filtering (list --tag) only matches a single tag at a time.
# Auth entry point
--tag feature:auth --tag layer:api --tag role:entrypoint --tag security:auth
# Database query
--tag feature:users --tag layer:data --tag role:repository
# Business logic
--tag feature:payments --tag layer:business --tag role:service
# Configuration
--tag layer:config --tag role:constant
Module/Package Tags (Language-Specific)
Always include the module or package context from the file path. Each language ecosystem has its own conventions—use the appropriate tag format.
Swift
- Tag:
module:<name>— Swift Package Manager module name - Inference: From
Sources/<ModuleName>/or target name in Package.swift | File path | Module tag | |-----------|------------| |Sources/AuthService/Validator.swift|--tag module:AuthService| |Sources/App/Models/User.swift|--tag module:App|
Rust
- Tag:
crate:<name>— For workspace crates (e.g.,crates/) - Tag:
module:<name>— For modules withinsrc/| File path | Module tag | |-----------|------------| |crates/auth/src/lib.rs|--tag crate:auth| |crates/auth/src/service.rs|--tag crate:auth --tag module:service| |src/auth/mod.rs|--tag module:auth| |src/auth/service.rs|--tag module:auth|
Go
- Tag:
package:<path>— Full package path relative to module root | File path | Module tag | |-----------|------------| |internal/auth/handler.go|--tag package:internal.auth| |pkg/api/middleware.go|--tag package:pkg.api| |cmd/server/main.go|--tag package:cmd.server| |handler.go(root) |--tag package:root|
Python
- Tag:
package:<path>— Python package path (dot notation) | File path | Module tag | |-----------|------------| |app/auth/service.py|--tag package:app.auth| |src/backend/db/models.py|--tag package:src.backend.db| |tests/test_auth.py|--tag package:tests|
TypeScript / JavaScript
- Tag:
module:<name>— Directory or workspace package name | File path | Module tag | |-----------|------------| |src/auth/service.ts|--tag module:auth| |packages/backend/src/db.ts|--tag module:backend| |components/auth/Login.tsx|--tag module:components.auth| |lib/api/client.ts|--tag module:lib.api|
Java
- Tag:
package:<name>— Java package name (dot notation) | File path | Module tag | |-----------|------------| |com/app/auth/AuthService.java|--tag package:com.app.auth| |org/mycompany/api/handler.java|--tag package:org.mycompany.api|
C#
- Tag:
namespace:<name>— C# namespace | File path | Module tag | |-----------|------------| |App.Auth/Services/AuthService.cs|--tag namespace:App.Auth.Services| |MyCompany.Data/Repositories/UserRepo.cs|--tag namespace:MyCompany.Data.Repositories|
Dart
- Tag:
package:<name>— Dart package name | File path | Module tag | |-----------|------------| |lib/auth/service.dart|--tag package:auth| |lib/models/user.dart|--tag package:models|
Example (Rust crate):
codemark add --file src/auth.rs --range 10 --note "Core JWT validation" --tag crate:auth --tag feature:auth --tag layer:business --tag role:validator
Example (Go package):
codemark add --file internal/auth/handler.go --range 25 --note "HTTP handler for authentication" --tag package:internal.auth --tag feature:auth --tag layer:api --tag role:handler
Quick Start
IMPORTANT: The
codemark addcommand requires--file <path>for all operations. The file path is NOT a positional argument.
Creating a tour/collection of bookmarks (recommended for agents)
Use --collection when creating bookmarks to add them directly to a tour. Always prefer range-based targeting as the first resource. Add multiple targeted notes with repeated --note (one per distinct aspect), and use --comment for task/ticket-specific discussion:
# 1. Preferred: Range-based targeting (Line or Point) — several focused notes
codemark add --file src/auth.rs --range 42 \
--note "Core auth entry point — all signed requests pass through here" \
--note "Verifies JWT signature and expiry" \
--collection login-flow --created-by claude
# 2. Alternative: Snippet-based (if range is unknown)
echo "func validateToken" | codemark add --file src/auth.swift --snippet --note "Validates JWT tokens" --note "Critical for security" --collection login-flow
# 3. Last Resort: Raw tree-sitter query (for extreme precision/disambiguation)
codemark add --file src/auth.swift --query '(function_declaration) @target' --note "Token validation function" --collection login-flow
# Notes = durable code explanation; comments = markdown discussion for this task/ticket
codemark add --file src/auth.rs --range 42 \
--note "Auth entry point; verifies signature" \
--comment "Touched while debugging **TICKET-42** — see [PR #116](https://github.com/org/repo/pull/116). Suspect race on token refresh." \
--collection login-flow
# Read the whole collection back as markdown (description, tags, links, steps + notes)
codemark tour show login-flow --format markdown
Method 1: Range-based bookmarking (Primary Resource)
When you know the file and line numbers. This leverages the Anchored Precision engine to automatically generate stable, architecturally-anchored queries.
# Point targeting: targets the smallest node at line 42, column 10
codemark add --file src/auth.rs --range 42:10 --note "Specific authorization gate" --created-by claude
# Line targeting: targets the tightest node containing line 42
codemark add --file src/auth.rs --range 42 --note "Core auth entry point" --created-by claude
# Span targeting: targets a specific range of lines
codemark add --file src/auth.rs --range 42-67 --note "Full login method" --created-by claude
# Precise Span targeting: targets a specific range of characters
codemark add --file src/auth.rs --range 10:5-10:20 --note "Specific expression" --created-by claude
Method 2: Snippet-based bookmarking
When you have the code snippet but need to find it in a file:
echo "func validateToken(_ token: String) -> Claims" | codemark add --file src/auth.swift --snippet --note "Validates JWT tokens" --tag role:validator --created-by claude
Method 3: Raw tree-sitter query (Last Resort)
Use this only if range-based targeting is ambiguous or you need a highly specific non-positional pattern.
codemark add --file src/auth.swift --query '(function_declaration name: (simple_identifier) @name (#eq? @name "validateToken")) @target' --note "Validates JWT tokens" --created-by claude
For common query patterns across languages, see:
queries/swift.mdqueries/rust.mdqueries/typescript.mdqueries/python.mdqueries/go.mdqueries/java.mdqueries/csharp.mdqueries/dart.mdqueries/common.md— Cross-language patterns and strategies
Best Practices
- Target small, specific code: Prefer single functions over entire classes, specific methods over whole modules. Smaller bookmarks are more resilient to refactoring, easier to understand, and more precise for navigation.
- Range-First Policy: Always prefer range-based targeting (
--range) as your first choice. It leverages the unified "Anchored Precision" engine to generate stable, architecturally-anchored queries automatically. Only use raw tree-sitter queries (--query) as a last resort if range-based targeting is ambiguous. - Fine-grained execution targeting: Don't just bookmark containers (classes/functions). Bookmark execution boundaries like critical method calls (
call_expression), authorization gates (if_statement), or complex state transitions (switch/match). - Granularity Strategy: We prefer more, highly specific bookmarks over fewer, general ones. For example, if a function performs three critical steps (auth, validation, DB write), it is better to bookmark those three specific lines/nodes than to bookmark the entire function.
- Use
--created-by <your-agent-slug>(claude,codex,copilot,pi) to distinguish your bookmarks from the user's — never the genericagent. See Author Identity. - Use
--collection <name>when creating bookmarks to add them directly to a tour (tours are auto-created if they don't exist). - Notes are durable, comments are ephemeral: explain the code with
--note; record task/ticket/debugging chatter with--comment. This keeps notes reusable in any future context instead of coupled to one agentic session. - Link out generously: attach related PRs, issues, design docs, dashboards, and external references to the collection with
codemark tour link add --kind ..., and embed inline links inside--commentmarkdown. This turns a collection into a self-contained briefing. - Always record the prompt on a collection: pass
--promptwith a cleaned-up, standalone restatement of the request that motivated the tour (fix the user's typos/grammar, keep their intent). It's the one field that lets the tour be rebuilt from intent later. See Recording the Prompt. - Tag collections, not just bookmarks:
codemark tour tag add(or--tagat create time) makes collections discoverable and gives the markdown overview useful metadata. - Gather context fast:
codemark tour show <name> --format markdownrenders the description, tags, links, and every step's ID + note in one shot — use it when restoring context from a previous session. - Iterative enhancement: When working with an existing bookmark and discover new context, use
editto add notes without re-parsing the file. Multiple agents can edit the same bookmark over time. - For detailed note guidelines, see
templates.md. - For usage examples, see
examples.md. - For tree-sitter query patterns, see
queries/directory for language-specific guides.
Commands Reference
Creating bookmarks
# By range (line or byte) — optionally add to tour
codemark add --file src/auth.rs --range 42-67 --collection my-work
# By snippet (reads from stdin) — optionally add to tour
echo "snippet here" | codemark add --file src/auth.rs --snippet --collection my-work
# By raw tree-sitter query (most precise) — optionally add to tour
codemark add --file src/auth.rs --query '(function_declaration) @target' --collection my-work
# With multiple notes (each creates a separate annotation entry)
codemark add --file src/auth.rs --range 42-67 --note "Primary observation" --note "Secondary note" --note "Action item" --collection my-work
# With a markdown comment for the current task/ticket (repeatable, kept separate from notes)
codemark add --file src/auth.rs --range 42 --note "Validates the session cookie" --comment "Part of **ENG-42** session-fixation fix." --collection my-work
# Preview what would be bookmarked (dry-run)
codemark add --file src/auth.rs --range 42 --dry-run
Notes vs. comments:
--noteis durable, reusable code explanation (rendered as plain prose).--commentis markdown discussion tied to a task/ticket/PR/debugging session (rendered as markdown, so links/lists/code blocks work). Keep task chatter in comments so notes stay clean and reusable across sessions.
Viewing bookmarks
# Show bookmark with preview (default output is JSON)
codemark show <bookmark-id>
# Human-readable markdown (notes, comments, metadata, resolution history)
codemark show <bookmark-id> --format markdown
# Show only file location (was 'resolve')
codemark show <bookmark-id> --location
The global --format flag accepts json (default), table, line, markdown, or a custom template, and can also be set via CODEMARK_FORMAT.
Load context
codemark list --health active
codemark list --author claude # substitute your own agent slug to find your bookmarks
codemark search "authentication"
Open bookmarked files
# Open a bookmark in your configured editor
codemark open <bookmark-id>
# The editor is configured via [open] section in .codemark/config.toml
# Supports placeholder substitution: {FILE}, {LINE_START}, {LINE_END}, {ID}
# Example: rs = "nvim +{LINE_START} {FILE}"
Organize with tours (collections)
Tag and link your collections — not just individual bookmarks. A well-tagged collection with links to the relevant PR, issue, and docs is far easier to rediscover and gives the next agent everything it needs.
# Tours are auto-created when using --collection, or create explicitly.
# Use --description for the collection's prose summary (collections have no --note).
# Use --prompt to record the request that motivated the tour (see Recording the Prompt).
codemark tour create login-flow \
--description "Step-by-step login execution path" \
--prompt "Trace the login execution path from the HTTP handler to the session write."
# Create with description, prompt, tags, and links in one command
codemark tour create auth-flow \
--description "End-to-end authentication flow" \
--prompt "Map the full authentication flow so we can audit it for the security review." \
--tag feature:auth --tag area:security \
--link "https://github.com/org/repo/pull/116,Auth refactor PR"
# Set or replace the prompt on an existing tour (single-valued: overwrites)
codemark tour annotate login-flow --prompt "Map login, including the 2FA branch."
# Remove a recorded prompt (an empty --prompt is rejected, so clearing is explicit)
codemark tour annotate login-flow --clear-prompt
# Tag an existing collection (repeatable)
codemark tour tag add login-flow feature:auth area:security
# Add links with a typed kind: pr | issue | doc | discussion | dashboard | repo | tour | other
codemark tour link add login-flow --url "https://github.com/org/repo/pull/116" --label "Auth PR" --kind pr
codemark tour link add login-flow --url "https://docs.example.com/auth" --label "Auth docs" --kind doc
codemark tour link add login-flow --url "https://linear.app/org/issue/ENG-42" --label "ENG-42" --kind issue
# Read a collection as markdown — description, tags, links, and each step's ID + note
codemark tour show login-flow --format markdown
# List all tours
codemark tour list
# Add existing bookmarks to a tour
codemark tour add login-flow <bookmark-id-1> <bookmark-id-2>
# Annotate a tour with tags/links/prompt (note: --note is NOT persisted on collections)
codemark tour annotate login-flow --tag phase:2 --link "https://example.com/runbook,Runbook"
# Publish / pull from Codetours
codemark tour push login-flow
codemark tour pull <tour-url>
Editing bookmarks
edit (and annotate) accept repeatable --note, --comment, and --tag, plus --context.
# Add durable notes, context, or tags to an existing bookmark
codemark edit <bookmark-id> --note "Additional context discovered during implementation"
codemark edit <bookmark-id> --context "Related to auth-refactor feature"
codemark edit <bookmark-id> --tag bug-fix --tag priority:high
# Add multiple notes at once (each --note creates a separate annotation)
codemark edit <bookmark-id> --note "First observation" --note "Second observation" --note "Third insight"
# Add a markdown comment scoped to the current task/ticket (kept separate from durable notes)
codemark edit <bookmark-id> --comment "Debugging **ENG-42**: this lock is held too long; see [trace](https://example.com/t/9)."
Health and maintenance
# Check bookmark health
codemark health status
# Run resolution (was 'heal')
codemark health check --auto-archive
# Remove old archived bookmarks
codemark health gc --older-than 30d
Data operations
# Export bookmarks
codemark data export --export-format json
# Import bookmarks
codemark data import backup.json
# Rebuild semantic search embeddings
codemark data reindex
Check impact
# See which bookmarks are affected by recent changes
codemark tour diff --since HEAD~3
Enriching Bookmark Context
High-quality context makes bookmarks discoverable and useful across sessions. Always enrich bookmarks with information that would help you or another agent find and understand the code later.
Module/Package Context (Required)
Always include module or package information inferred from the file path. This is critical for finding bookmarks by their location in the codebase.
# Infer from file path and add as context
codemark add --file src/auth/service.rs --range 42 --context "Module: auth | Package: service" --note "Core JWT validation" --tag module:auth
| Language | Path pattern | Module context |
|---|---|---|
| Rust | crates/auth/src/lib.rs |
crate:auth |
| Rust | src/auth/service.rs |
module:auth |
| Go | internal/auth/handler.go |
package:internal.auth |
| Python | app/auth/service.py |
package:app.auth |
| TypeScript | src/auth/service.ts |
module:auth |
| Java | com/app/auth/AuthService.java |
package:com.app.auth |
| Swift | Sources/AuthService/ |
module:AuthService |
Domain Context
Explain which business domain or bounded context this code belongs to.
codemark edit <id> --context "Domain: User authentication | Bounded context: Identity and Access Management"
Usage Context
Document where and how this code is used.
codemark edit <id> --context "Used by: API middleware, websocket handler, cron jobs"
Evolution Context
Track the lifecycle and evolution of the code.
codemark edit <id> --context "Added in: v2.3.0 | Deprecated in: v3.0.0 | Replacement: src/auth/v2/"
Dependency Context
Link to related bookmarks and dependencies.
codemark edit <id> --context "Depends on: [[bookmark-id-claims]] | Called by: [[bookmark-id-middleware]]"
Performance Context
Note performance characteristics when relevant.
codemark edit <id> --context "Performance: O(n) where n = user roles | Cache: 30s TTL"
Security Context
For security-sensitive code, document security considerations.
codemark edit <id> --context "Security: Validates JWT signature | Checks expiry | Handles token rotation"
Context Template
When creating or editing bookmarks, use this template:
Context: <domain> | <usage> | <dependencies> | <security/evolution notes>
Examples:
Context: Auth domain | Validates all API requests | Depends on Claims structContext: Payment processing | Called by checkout flow | External: Stripe APIContext: User preferences | Cached 30s | DB: users_table
Supported languages
Swift, Rust, TypeScript, Python, Go, Java, C#, Dart (built-in).
Eleven more are one command away from the grammar registry: Bash, C#, Go, Lua, PHP, Python, Ruby, Scala, Swift, TypeScript, Zig. Anything else loads at runtime from a WASM grammar — no recompile needed.
When a grammar is missing, install it
If a command fails with "no grammar installed for <lang>", the bookmark is
not broken — codemark simply cannot parse that language yet. Install it and
retry, without asking first:
codemark languages install <lang> # downloads, verifies the SHA-256, installs
This is safe to do on the user's behalf: it writes only to the grammar cache and verifies the published SHA-256 before installing.
Mention it when the grammar replaces a built-in. Some registry entries —
Python, Go, C#, Swift, TypeScript — are richer profiles for languages codemark
already ships, and installing one takes over that extension for every
bookmark in the repo. The registry entry carries its own consent, so no extra
flag is needed and the install just succeeds; say which built-in was replaced
so the user isn't surprised. codemark languages list afterwards shows both
entries, the dynamic one owning the extension.
Stop and ask if the language isn't in the registry. Building a grammar is a much larger task — see Adding a new language below, and confirm before starting.
The same error appears when opening a shared tour for a language you lack. That is the common case, not an edge case: a pack travels with bookmarks, not grammars. Install and continue.
Adding a new language (WASM grammar)
When the user wants to bookmark a language not listed above, install a Tree-sitter
WASM grammar. Do not edit the Language enum or any Rust source — grammars
load dynamically.
Two parts: the grammar (a .wasm you build) and the profile (the node
kinds that make it useful). The grammar is mechanical; the profile is where
mistakes hide, so check the registry before writing one by hand.
0. Try the registry first — it may be one command
codemark languages registry list
codemark languages install ruby # downloads, verifies, installs
If the language is listed with a prebuilt grammar, you are done: no build toolchain, no manual download, and the curated profile comes with it. Everything below is for a language the registry doesn't cover.
1. Find the grammar
Tree-sitter has no search command, and grammars live in many repos. In order of usefulness:
- nvim-treesitter
parsers.lua— ~570 parsers, machine-readable, each with a repo URL and a pinned revision. The only source that gives you a revision, which is what you want for reproducible builds (and forgrammar_revif contributing to the registry). Entries look like:ruby = { install_info = { url = 'https://github.com/tree-sitter/tree-sitter-ruby', revision = 'ad907a69da0c8a4f7a943a7fe012712208da6dee' } } - tree-sitter wiki: List of parsers — the canonical list, with an ABI column. No revisions.
- github.com/tree-sitter — ~24 first-party grammars. Best quality, narrowest coverage.
2. Get a .wasm, then add it (mechanical)
Codemark accepts ABI 13–15 (roughly CLI 0.21–0.25). Tree-sitter is
backwards- but not forwards-compatible, so only a .wasm from a CLI newer
than codemark's runtime is rejected. Building with 0.25 is the safe default
because it can never be too new.
A prebuilt .wasm from the grammar's GitHub releases usually works and skips
the Docker/emcc step — try it first; add rejects an incompatible module up
front, so there's no risk in attempting it. Otherwise build from source:
npm install -g tree-sitter-cli@0.25 # or cargo install tree-sitter-cli --version ^0.25
# Check out the pinned revision, not the default branch — node kinds change
# between grammar versions, so an unpinned build may not match the profile.
git clone --depth 1 --branch v0.23.1 https://github.com/tree-sitter/tree-sitter-ruby
cd tree-sitter-ruby
tree-sitter build --wasm # needs Docker or emscripten; emits tree-sitter-ruby.wasm
codemark languages add --name ruby --extensions rb,rake ./tree-sitter-ruby.wasm
(For a revision that's a commit rather than a tag, git clone then
git checkout <sha> — --branch only accepts refs.)
add validates the .wasm by loading it through the WasmStore, rejecting an
incompatible module, then writes the manifest and installs atomically. WASM
grammar loading is enabled in the default build; only a --no-default-features
build lacks it (the CLI then warns the grammar installs but is ignored at
runtime).
3. Get the profile — try these in order
add on its own writes an empty profile. Parsing works immediately, but
breadcrumbs and query summaries stay weak until it's filled. Do not jump
straight to hand-writing it; that's the last resort, not the first move.
a. Check the registry first. Someone may have already curated and verified a profile for this language:
codemark languages registry list
codemark languages add ./tree-sitter-ruby.wasm --from-registry ruby
With --from-registry, --name and --extensions are optional (the registry
supplies them) and still win as overrides. If the language is listed, you are
done — stop here.
b. Generate one from samples. If it isn't in the registry, derive the profile from a real parse instead of guessing:
# needs a build with --features profile-authoring
codemark languages profile init ./tree-sitter-ruby.wasm \
--sample example.rb --name ruby --extensions rb,rake
This prints the proposed manifest plus an evidence table (each node kind,
how often it appeared, whether it became a landmark, which field held its name,
and why). Read the table before accepting — that's what it's for. --out <file>
writes the manifest instead of printing it. Nothing is written to the grammar
cache either way.
c. Hand-write it only if neither is available. Inspect the AST first:
tree-sitter parse example.rb # shows this grammar's actual node kinds
"profile": {
// node kinds that anchor a structural query (functions, classes, types…)
"landmark_kinds": ["method", "class", "module", "singleton_method"],
// node kind → human label (drives query summaries + TUI icons)
"node_labels": { "method": "function", "class": "class", "call": "call" },
// [container node kind, name-field] — ancestors that make good breadcrumbs
"containers": [["class", "name"], ["method", "name"], ["module", "name"]]
}
The manifest path is printed by add; codemark languages list shows it, or
~/Library/Caches/codemark/grammars/<name>/manifest.json on macOS,
~/.cache/... on Linux.
4. Verify — a wrong profile fails silently
Always run validate after touching a profile. Node kinds are
grammar-specific and a wrong one does not raise an error at runtime: a bad
landmark_kinds quietly falls back to a built-in set, and a bad containers
just stops producing breadcrumbs.
validate checks that each node kind is defined by the grammar, and that each
container field exists somewhere in it. It cannot check that a field belongs
to its paired kind — tree-sitter exposes field names globally — so
["mod_item", "value"] passes. That gap is cosmetic: breadcrumbs match on the
node kind alone and never read the field.
What does matter is containers[].0. Get the kind wrong and the ancestor never
matches, so breadcrumbs go blank with no error.
So after validating, create a new bookmark nested inside the container and
inspect it. codemark show renders breadcrumbs stored at resolution time, so an
existing bookmark reports what the old profile produced, and --dry-run
saves nothing to show:
codemark languages validate
# A line inside a method inside a class — not a top-level one, which
# exercises nothing.
codemark add --file example.rb --range 14 --created-by claude
codemark show <id> --format table | grep Context
A blank Context on a line that really is nested means a containers entry
isn't matching.
Found issues with installed grammars:
- .../lua: error: profile.landmark_kinds[1]: node kind 'function_item' is not
defined by this grammar, so it can never match
- .../lua: error: profile.containers[0].1: 'label' is not a field in this
grammar, so the container entry for 'function_declaration' names something
that doesn't exist
Close misses get a suggestion ('local_function_declaration' … did you mean 'function_declaration'?).
An error blocks the install. A warning (unknown key, no containers) still works but is probably not what you meant.
The error kinds differ: an unknown node kind can never match, and a wrong
containers[].0 is the usual cause of blank breadcrumbs. An unknown container
field blocks installation but doesn't affect matching — breadcrumb extraction
reads only the kind — so it's never the reason breadcrumbs are missing.
Never copy node kinds from another language. Ruby says method, Rust
function_item, Python function_definition, Lua function_declaration — and
Lua has function_call, not call_expression. A committed fixture once carried
five kinds that did not exist in its grammar, which silently disabled Lua
breadcrumbs entirely. Reference: tests/fixtures/grammars/lua/manifest.json.
Full details: dev-docs/guides/adding-wasm-grammars.md.
Version History
-
0.7.30
Current 2026-11-02 11:49
新增文档说明 profile 如何影响查询,并支持安装语法解析器;引入 grammar profile registry 用于 lint、生成和获取配置文件;记录驱动 collection 创建的 prompt。
-
0.7.27
2026-08-02 22:26
默认启用 wasm 语法树加载器
-
0.7.26
2026-07-31 14:36
移除GitHub语法安装逻辑,保留机械添加路径,优化技能发现机制。
- 0.7.23 2026-07-19 09:03


