opencode stuff

This commit is contained in:
2026-01-23 21:33:04 +00:00
parent e0b317cdf3
commit 647943abbc
15 changed files with 1389 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
---
name: librarian
description: Multi-repository codebase exploration. Research library internals, find code patterns, understand architecture, compare implementations across GitHub/npm/PyPI/crates. Use when needing deep understanding of how libraries work, finding implementations across open source, or exploring remote repository structure.
references:
- references/tool-routing.md
- references/opensrc-api.md
- references/opensrc-examples.md
- references/linking.md
- references/diagrams.md
---
# Librarian Skill
Deep codebase exploration across remote repositories.
## How to Use This Skill
### Reference Structure
| File | Purpose | When to Read |
|------|---------|--------------|
| `tool-routing.md` | Tool selection decision trees | **Always read first** |
| `opensrc-api.md` | API reference, types | Writing opensrc code |
| `opensrc-examples.md` | JavaScript patterns, workflows | Implementation examples |
| `linking.md` | GitHub URL patterns | Formatting responses |
| `diagrams.md` | Mermaid patterns | Visualizing architecture |
### Reading Order
1. **Start** with `tool-routing.md` → choose tool strategy
2. **If using opensrc:**
- Read `opensrc-api.md` for API details
- Read `opensrc-examples.md` for patterns
3. **Before responding:** `linking.md` + `diagrams.md` for output formatting
## Tool Arsenal
| Tool | Best For | Limitations |
|------|----------|-------------|
| **grep_app** | Find patterns across ALL public GitHub | Literal search only |
| **context7** | Library docs, API examples, usage | Known libraries only |
| **opensrc** | Fetch full source for deep exploration | Must fetch before read |
## Quick Decision Trees
### "How does X work?"
```
Known library?
├─ Yes → context7.resolve-library-id → context7.query-docs
│ └─ Need internals? → opensrc.fetch → read source
└─ No → grep_app search → opensrc.fetch top result
```
### "Find pattern X"
```
Specific repo?
├─ Yes → opensrc.fetch → opensrc.grep → read matches
└─ No → grep_app (broad) → opensrc.fetch interesting repos
```
### "Explore repo structure"
```
1. opensrc.fetch(target)
2. opensrc.tree(source.name) → quick overview
3. opensrc.files(source.name, "**/*.ts") → detailed listing
4. Read: README, package.json, src/index.*
5. Create architecture diagram (see diagrams.md)
```
### "Compare X vs Y"
```
1. opensrc.fetch(["X", "Y"])
2. Use source.name from results for subsequent calls
3. opensrc.grep(pattern, { sources: [nameX, nameY] })
4. Read comparable files, synthesize differences
```
## Critical: Source Naming Convention
**After fetching, always use `source.name` for subsequent calls:**
```javascript
const [{ source }] = await opensrc.fetch("vercel/ai");
const files = await opensrc.files(source.name, "**/*.ts");
```
| Type | Fetch Spec | Source Name |
|------|------------|-------------|
| npm | `"zod"` | `"zod"` |
| npm scoped | `"@tanstack/react-query"` | `"@tanstack/react-query"` |
| pypi | `"pypi:requests"` | `"requests"` |
| crates | `"crates:serde"` | `"serde"` |
| GitHub | `"vercel/ai"` | `"github.com/vercel/ai"` |
| GitLab | `"gitlab:org/repo"` | `"gitlab.com/org/repo"` |
## When NOT to Use opensrc
| Scenario | Use Instead |
|----------|-------------|
| Simple library API questions | context7 |
| Finding examples across many repos | grep_app |
| Very large monorepos (>10GB) | Clone locally |
| Private repositories | Direct access |
## Output Guidelines
1. **Comprehensive final message** - only last message returns to main agent
2. **Parallel tool calls** - maximize efficiency
3. **Link every file reference** - see `linking.md`
4. **Diagram complex relationships** - see `diagrams.md`
5. **Never mention tool names** - say "I'll search" not "I'll use opensrc"
## References
- [Tool Routing Decision Trees](references/tool-routing.md)
- [opensrc API Reference](references/opensrc-api.md)
- [opensrc Code Examples](references/opensrc-examples.md)
- [GitHub Linking Patterns](references/linking.md)
- [Mermaid Diagram Patterns](references/diagrams.md)

View File

@@ -0,0 +1,51 @@
# Mermaid Diagram Patterns
Create diagrams for:
- Architecture (component relationships)
- Data flow (request → response)
- Dependencies (import graph)
- Sequences (step-by-step processes)
## Architecture
```mermaid
graph TD
A[Client] --> B[API Gateway]
B --> C[Auth Service]
B --> D[Data Service]
D --> E[(Database)]
```
## Flow
```mermaid
flowchart LR
Input --> Parse --> Validate --> Transform --> Output
```
## Sequence
```mermaid
sequenceDiagram
Client->>+Server: Request
Server->>+DB: Query
DB-->>-Server: Result
Server-->>-Client: Response
```
## When to Use
| Type | Use For |
|------|---------|
| `graph TD` | Component hierarchy, dependencies |
| `flowchart LR` | Data transformation, pipelines |
| `sequenceDiagram` | Request/response, multi-party interaction |
| `classDiagram` | Type relationships, inheritance |
| `stateDiagram` | State machines, lifecycle |
## Tips
- Keep nodes short (3-4 words max)
- Use subgraphs for grouping related components
- Arrow labels for relationship types
- Prefer LR (left-right) for flows, TD (top-down) for hierarchies

View File

@@ -0,0 +1,61 @@
# GitHub Linking Patterns
All file/dir/code refs → fluent markdown links. Never raw URLs.
## URL Formats
### File
```
https://github.com/{owner}/{repo}/blob/{ref}/{path}
```
### File + Lines
```
https://github.com/{owner}/{repo}/blob/{ref}/{path}#L{start}-L{end}
```
### Directory
```
https://github.com/{owner}/{repo}/tree/{ref}/{path}
```
### GitLab (note `/-/blob/`)
```
https://gitlab.com/{owner}/{repo}/-/blob/{ref}/{path}
```
## Ref Resolution
| Source | Use as ref |
|--------|------------|
| Known version | `v{version}` |
| Default branch | `main` or `master` |
| opensrc fetch | ref from result |
| Specific commit | full SHA |
## Examples
### Correct
```markdown
The [`parseAsync`](https://github.com/colinhacks/zod/blob/main/src/types.ts#L450-L480) method handles...
```
### Wrong
```markdown
See https://github.com/colinhacks/zod/blob/main/src/types.ts#L100
The parseAsync method in src/types.ts handles...
```
## Line Numbers
- Single: `#L42`
- Range: `#L42-L50`
- Prefer ranges for context (2-5 lines around key code)
## Registry → GitHub
| Registry | Find repo in |
|----------|--------------|
| npm | `package.json``repository` |
| PyPI | `pyproject.toml` or setup.py |
| crates | `Cargo.toml` |

View File

@@ -0,0 +1,235 @@
# opensrc API Reference
## Tool
Use the **opensrc MCP server** via single tool:
| Tool | Purpose |
|------|---------|
| `opensrc_execute` | All operations (fetch, read, grep, files, remove, etc.) |
Takes a `code` parameter: JavaScript async arrow function executed server-side. Source trees stay on server, only results return.
## API Surface
### Read Operations
```typescript
// List all fetched sources
opensrc.list(): Source[]
// Check if source exists
opensrc.has(name: string, version?: string): boolean
// Get source metadata
opensrc.get(name: string): Source | undefined
// List files with optional glob
opensrc.files(sourceName: string, glob?: string): Promise<FileEntry[]>
// Get directory tree structure (default depth: 3)
opensrc.tree(sourceName: string, options?: { depth?: number }): Promise<TreeNode>
// Regex search file contents
opensrc.grep(pattern: string, options?: GrepOptions): Promise<GrepResult[]>
// AST-based semantic code search
opensrc.astGrep(sourceName: string, pattern: string, options?: AstGrepOptions): Promise<AstGrepMatch[]>
// Read single file
opensrc.read(sourceName: string, filePath: string): Promise<string>
// Batch read multiple files (supports globs!)
opensrc.readMany(sourceName: string, paths: string[]): Promise<Record<string, string>>
// Parse fetch spec
opensrc.resolve(spec: string): Promise<ParsedSpec>
```
### Mutation Operations
```typescript
// Fetch packages/repos
opensrc.fetch(specs: string | string[], options?: { modify?: boolean }): Promise<FetchedSource[]>
// Remove sources
opensrc.remove(names: string[]): Promise<RemoveResult>
// Clean by type
opensrc.clean(options?: CleanOptions): Promise<RemoveResult>
```
## Types
### Source
```typescript
interface Source {
type: "npm" | "pypi" | "crates" | "repo";
name: string; // Use this for all subsequent calls
version?: string;
ref?: string;
path: string;
fetchedAt: string;
repository: string;
}
```
### FetchedSource
```typescript
interface FetchedSource {
source: Source; // IMPORTANT: use source.name for subsequent calls
alreadyExists: boolean;
}
```
### GrepOptions
```typescript
interface GrepOptions {
sources?: string[]; // Filter to specific sources
include?: string; // File glob pattern (e.g., "*.ts")
maxResults?: number; // Limit results (default: 100)
}
```
### GrepResult
```typescript
interface GrepResult {
source: string;
file: string;
line: number;
content: string;
}
```
### AstGrepOptions
```typescript
interface AstGrepOptions {
glob?: string; // File glob pattern (e.g., "**/*.ts")
lang?: string | string[]; // Language(s): "js", "ts", "tsx", "html", "css"
limit?: number; // Max results (default: 1000)
}
```
### AstGrepMatch
```typescript
interface AstGrepMatch {
file: string;
line: number;
column: number;
endLine: number;
endColumn: number;
text: string; // Matched code text
metavars: Record<string, string>; // Captured $VAR → text
}
```
#### AST Pattern Syntax
| Pattern | Matches |
|---------|---------|
| `$NAME` | Single node, captures to metavars |
| `$$$ARGS` | Zero or more nodes (variadic), captures |
| `$_` | Single node, no capture |
| `$$$` | Zero or more nodes, no capture |
### FileEntry
```typescript
interface FileEntry {
path: string;
size: number;
isDirectory: boolean;
}
```
### TreeNode
```typescript
interface TreeNode {
name: string;
type: "file" | "dir";
children?: TreeNode[]; // only for dirs
}
```
### CleanOptions
```typescript
interface CleanOptions {
packages?: boolean;
repos?: boolean;
npm?: boolean;
pypi?: boolean;
crates?: boolean;
}
```
### RemoveResult
```typescript
interface RemoveResult {
success: boolean;
removed: string[];
}
```
## Error Handling
Operations throw on errors. Wrap in try/catch if needed:
```javascript
async () => {
try {
const content = await opensrc.read("zod", "missing.ts");
return content;
} catch (e) {
return { error: e.message };
}
}
```
`readMany` returns errors as string values prefixed with `[Error:`:
```javascript
const files = await opensrc.readMany("zod", ["exists.ts", "missing.ts"]);
// { "exists.ts": "content...", "missing.ts": "[Error: ENOENT...]" }
// Filter successful reads
const successful = Object.entries(files)
.filter(([_, content]) => !content.startsWith("[Error:"));
```
## Package Spec Formats
| Format | Example | Source Name After Fetch |
|--------|---------|------------------------|
| `<name>` | `"zod"` | `"zod"` |
| `<name>@<version>` | `"zod@3.22.0"` | `"zod"` |
| `pypi:<name>` | `"pypi:requests"` | `"requests"` |
| `crates:<name>` | `"crates:serde"` | `"serde"` |
| `owner/repo` | `"vercel/ai"` | `"github.com/vercel/ai"` |
| `owner/repo@ref` | `"vercel/ai@v1.0.0"` | `"github.com/vercel/ai"` |
| `gitlab:owner/repo` | `"gitlab:org/repo"` | `"gitlab.com/org/repo"` |
## Critical Pattern
**Always capture `source.name` from fetch results:**
```javascript
async () => {
const [{ source }] = await opensrc.fetch("vercel/ai");
// GitHub repos: "vercel/ai" → "github.com/vercel/ai"
const sourceName = source.name;
// Use sourceName for ALL subsequent calls
const files = await opensrc.files(sourceName, "src/**/*.ts");
return files;
}
```

View File

@@ -0,0 +1,336 @@
# opensrc Code Examples
## Workflow: Fetch → Explore
### Basic Fetch and Explore with tree()
```javascript
async () => {
const [{ source }] = await opensrc.fetch("vercel/ai");
// Get directory structure first
const tree = await opensrc.tree(source.name, { depth: 2 });
return tree;
}
```
### Fetch and Read Key Files
```javascript
async () => {
const [{ source }] = await opensrc.fetch("vercel/ai");
const sourceName = source.name; // "github.com/vercel/ai"
const files = await opensrc.readMany(sourceName, [
"package.json",
"README.md",
"src/index.ts"
]);
return { sourceName, files };
}
```
### readMany with Globs
```javascript
async () => {
const [{ source }] = await opensrc.fetch("zod");
// Read all package.json files in monorepo
const files = await opensrc.readMany(source.name, [
"packages/*/package.json" // globs supported!
]);
return Object.keys(files);
}
```
### Batch Fetch Multiple Packages
```javascript
async () => {
const results = await opensrc.fetch(["zod", "valibot", "yup"]);
const names = results.map(r => r.source.name);
// Compare how each handles string validation
const comparisons = {};
for (const name of names) {
const matches = await opensrc.grep("string.*validate|validateString", {
sources: [name],
include: "*.ts",
maxResults: 10
});
comparisons[name] = matches.map(m => `${m.file}:${m.line}`);
}
return comparisons;
}
```
## Search Patterns
### Grep → Read Context
```javascript
async () => {
const matches = await opensrc.grep("export function parse\\(", {
sources: ["zod"],
include: "*.ts"
});
if (matches.length === 0) return "No matches";
const match = matches[0];
const content = await opensrc.read(match.source, match.file);
const lines = content.split("\n");
// Return 40 lines starting from match
return {
file: match.file,
code: lines.slice(match.line - 1, match.line + 39).join("\n")
};
}
```
### Search Across All Fetched Sources
```javascript
async () => {
const sources = opensrc.list();
const results = {};
for (const source of sources) {
const errorHandling = await opensrc.grep("throw new|catch \\(|\\.catch\\(", {
sources: [source.name],
include: "*.ts",
maxResults: 20
});
results[source.name] = {
type: source.type,
errorPatterns: errorHandling.length
};
}
return results;
}
```
## AST-Based Search
Use `astGrep` for semantic code search with pattern matching.
### Find Function Declarations
```javascript
async () => {
const [{ source }] = await opensrc.fetch("lodash");
const fns = await opensrc.astGrep(source.name, "function $NAME($$$ARGS) { $$$BODY }", {
lang: "js",
limit: 20
});
return fns.map(m => ({
file: m.file,
line: m.line,
name: m.metavars.NAME
}));
}
```
### Find React Hooks Usage
```javascript
async () => {
const [{ source }] = await opensrc.fetch("vercel/ai");
const stateHooks = await opensrc.astGrep(
source.name,
"const [$STATE, $SETTER] = useState($$$INIT)",
{ lang: ["ts", "tsx"], limit: 50 }
);
return stateHooks.map(m => ({
file: m.file,
state: m.metavars.STATE,
setter: m.metavars.SETTER
}));
}
```
### Find Class Definitions with Context
```javascript
async () => {
const [{ source }] = await opensrc.fetch("zod");
const classes = await opensrc.astGrep(source.name, "class $NAME", {
glob: "**/*.ts"
});
const details = [];
for (const cls of classes.slice(0, 5)) {
const content = await opensrc.read(source.name, cls.file);
const lines = content.split("\n");
details.push({
name: cls.metavars.NAME,
file: cls.file,
preview: lines.slice(cls.line - 1, cls.line + 9).join("\n")
});
}
return details;
}
```
### Compare Export Patterns Across Libraries
```javascript
async () => {
const results = await opensrc.fetch(["zod", "valibot"]);
const names = results.map(r => r.source.name);
const exports = {};
for (const name of names) {
const matches = await opensrc.astGrep(name, "export const $NAME = $_", {
lang: "ts",
limit: 30
});
exports[name] = matches.map(m => m.metavars.NAME);
}
return exports;
}
```
### grep vs astGrep
| Use Case | Tool |
|----------|------|
| Text/regex pattern | `grep` |
| Function declarations | `astGrep`: `function $NAME($$$) { $$$ }` |
| Arrow functions | `astGrep`: `const $N = ($$$) => $_` |
| Class definitions | `astGrep`: `class $NAME extends $PARENT` |
| Import statements | `astGrep`: `import { $$$IMPORTS } from "$MOD"` |
| JSX components | `astGrep`: `<$COMP $$$PROPS />` |
## Repository Exploration
### Find Entry Points
```javascript
async () => {
const name = "github.com/vercel/ai";
const allFiles = await opensrc.files(name, "**/*.{ts,js}");
const entryPoints = allFiles.filter(f =>
f.path.match(/^(src\/)?(index|main|mod)\.(ts|js)$/) ||
f.path.includes("/index.ts")
);
// Read all entry points
const contents = {};
for (const ep of entryPoints.slice(0, 5)) {
contents[ep.path] = await opensrc.read(name, ep.path);
}
return {
totalFiles: allFiles.length,
entryPoints: entryPoints.map(f => f.path),
contents
};
}
```
### Explore Package Structure
```javascript
async () => {
const name = "zod";
// Get all TypeScript files
const tsFiles = await opensrc.files(name, "**/*.ts");
// Group by directory
const byDir = {};
for (const f of tsFiles) {
const dir = f.path.split("/").slice(0, -1).join("/") || ".";
byDir[dir] = (byDir[dir] || 0) + 1;
}
// Read key files
const pkg = await opensrc.read(name, "package.json");
const readme = await opensrc.read(name, "README.md");
return {
structure: byDir,
package: JSON.parse(pkg),
readmePreview: readme.slice(0, 500)
};
}
```
## Batch Operations
### Read Many with Error Handling
```javascript
async () => {
const files = await opensrc.readMany("zod", [
"src/index.ts",
"src/types.ts",
"src/ZodError.ts",
"src/helpers/parseUtil.ts"
]);
// files is Record<string, string> - errors start with "[Error:"
const successful = Object.entries(files)
.filter(([_, content]) => !content.startsWith("[Error:"))
.map(([path, content]) => ({ path, lines: content.split("\n").length }));
return successful;
}
```
### Parallel Grep Across Multiple Sources
```javascript
async () => {
const targets = ["zod", "valibot"];
const pattern = "export (type|interface)";
const results = await Promise.all(
targets.map(async (name) => {
const matches = await opensrc.grep(pattern, {
sources: [name],
include: "*.ts",
maxResults: 50
});
return { name, count: matches.length, matches };
})
);
return results;
}
```
## Workflow Checklist
### Comprehensive Repository Analysis
```
Repository Analysis Progress:
- [ ] 1. Fetch repository
- [ ] 2. Read package.json + README
- [ ] 3. Identify entry points (src/index.*)
- [ ] 4. Read main entry file
- [ ] 5. Map exports and public API
- [ ] 6. Trace key functionality
- [ ] 7. Create architecture diagram
```
### Library Comparison
```
Comparison Progress:
- [ ] 1. Fetch all libraries
- [ ] 2. Grep for target pattern in each
- [ ] 3. Read matching implementations
- [ ] 4. Create comparison table
- [ ] 5. Synthesize findings
```

View File

@@ -0,0 +1,109 @@
# Tool Routing
## Decision Flowchart
```mermaid
graph TD
Q[User Query] --> T{Query Type?}
T -->|Understand/Explain| U[UNDERSTAND]
T -->|Find/Search| F[FIND]
T -->|Explore/Architecture| E[EXPLORE]
T -->|Compare| C[COMPARE]
U --> U1{Known library?}
U1 -->|Yes| U2[context7.resolve-library-id]
U2 --> U3[context7.query-docs]
U3 --> U4{Need source?}
U4 -->|Yes| U5[opensrc.fetch → read]
U1 -->|No| U6[grep_app → opensrc.fetch]
F --> F1{Specific repo?}
F1 -->|Yes| F2[opensrc.fetch → grep → read]
F1 -->|No| F3[grep_app broad search]
F3 --> F4[opensrc.fetch interesting repos]
E --> E1[opensrc.fetch]
E1 --> E2[opensrc.files]
E2 --> E3[Read entry points]
E3 --> E4[Create diagram]
C --> C1["opensrc.fetch([X, Y])"]
C1 --> C2[grep same pattern]
C2 --> C3[Read comparable files]
C3 --> C4[Synthesize comparison]
```
## Query Type Detection
| Keywords | Query Type | Start With |
|----------|------------|------------|
| "how does", "why does", "explain", "purpose of" | UNDERSTAND | context7 |
| "find", "where is", "implementations of", "examples of" | FIND | grep_app |
| "explore", "walk through", "architecture", "structure" | EXPLORE | opensrc |
| "compare", "vs", "difference between" | COMPARE | opensrc |
## UNDERSTAND Queries
```
Known library? → context7.resolve-library-id → context7.query-docs
└─ Need source? → opensrc.fetch → read
Unknown? → grep_app search → opensrc.fetch top result → read
```
**When to transition context7 → opensrc:**
- Need implementation details (not just API docs)
- Question about internals/private methods
- Tracing code flow through library
## FIND Queries
```
Specific repo? → opensrc.fetch → opensrc.grep → read matches
Broad search? → grep_app → analyze → opensrc.fetch interesting repos
```
**grep_app query tips:**
- Use literal code patterns: `useState(` not "react hooks"
- Filter by language: `language: ["TypeScript"]`
- Narrow by repo: `repo: "vercel/"` for org
## EXPLORE Queries
```
1. opensrc.fetch(target)
2. opensrc.files → understand structure
3. Identify entry points: README, package.json, src/index.*
4. Read entry → internals
5. Create architecture diagram
```
## COMPARE Queries
```
1. opensrc.fetch([X, Y])
2. Extract source.name from each result
3. opensrc.grep same pattern in both
4. Read comparable files
5. Synthesize → comparison table
```
## Tool Capabilities
| Tool | Best For | Not For |
|------|----------|---------|
| **grep_app** | Broad search, unknown scope, finding repos | Semantic queries |
| **context7** | Library APIs, best practices, common patterns | Library internals |
| **opensrc** | Deep exploration, reading internals, tracing flow | Initial discovery |
## Anti-patterns
| Don't | Do |
|-------|-----|
| grep_app for known library docs | context7 first |
| opensrc.fetch before knowing target | grep_app to discover |
| Multiple small reads | opensrc.readMany batch |
| Describe without linking | Link every file ref |
| Text for complex relationships | Mermaid diagram |
| Use tool names in responses | "I'll search..." not "I'll use opensrc" |

View File

@@ -0,0 +1,122 @@
---
name: session-export
description: Update GitHub PR descriptions with AI session export summaries. Use when user asks to add session summary to PR/MR, document AI assistance in PR/MR, or export conversation summary to PR/MR description.
---
# Session Export
Update PR/MR descriptions with a structured summary of the AI-assisted conversation.
## Output Format
```markdown
> [!NOTE]
> This PR was written with AI assistance.
<details><summary>AI Session Export</summary>
<p>
```json
{
"info": {
"title": "<brief task description>",
"agent": "opencode",
"models": ["<model(s) used>"]
},
"summary": [
"<action 1>",
"<action 2>",
...
]
}
```
</p>
</details>
```
## Workflow
### 1. Export Session Data
Get session data using OpenCode CLI:
```bash
opencode export [sessionID]
```
Returns JSON with session info including models used. Use current session if no sessionID provided.
### 2. Generate Summary JSON
From exported data and conversation context, create summary:
- **title**: 2-5 word task description (lowercase)
- **agent**: always "opencode"
- **models**: array from export data
- **summary**: array of terse action statements
- Use past tense ("added", "fixed", "created")
- Start with "user requested..." or "user asked..."
- Chronological order
- Attempt to keep the summary to a max of 25 turns ("user requested", "agent did")
- **NEVER include sensitive data**: API keys, credentials, secrets, tokens, passwords, env vars
### 3. Update PR/MR Description
**GitHub:**
```bash
gh pr edit <PR_NUMBER> --body "$(cat <<'EOF'
<existing description>
> [!NOTE]
> This PR was written with AI assistance.
<details><summary>AI Session Export</summary>
...
</details>
EOF
)"
```
### 4. Preserve Existing Content
Always fetch and preserve existing PR/MR description:
```bash
# GitHub
gh pr view <PR_NUMBER> --json body -q '.body'
Append session export after existing content with blank line separator.
## Example Summary
For a session where user asked to add dark mode:
```json
{
"info": {
"title": "dark mode implementation",
"agent": "opencode",
"models": ["claude sonnet 4"]
},
"summary": [
"user requested dark mode toggle in settings",
"agent explored existing theme system",
"agent created ThemeContext for state management",
"agent added DarkModeToggle component",
"agent updated CSS variables for dark theme",
"agent ran tests and fixed 2 failures",
"agent committed changes"
]
}
```
## Security
**NEVER include in summary:**
- API keys, tokens, secrets
- Passwords, credentials
- Environment variable values
- Private URLs with auth tokens
- Personal identifiable information
- Internal hostnames/IPs

View File

@@ -0,0 +1,70 @@
---
name: vcs-detect
description: Detect whether the current project uses jj (Jujutsu) or git for version control. Run this BEFORE any VCS command to use the correct tool.
---
# VCS Detection Skill
Detect the version control system in use before running any VCS commands.
## Why This Matters
- jj (Jujutsu) and git have different CLIs and workflows
- Running `git` commands in a jj repo (or vice versa) causes errors
- Some repos use jj with git colocated (both `.jj/` and `.git/` exist)
## Detection Logic
Both `jj root` and `git rev-parse --show-toplevel` walk up the filesystem to find repo root.
**Priority order:**
1. `jj root` succeeds → jj (handles colocated too)
2. `git rev-parse` succeeds → git
3. Both fail → no VCS
## Detection Command
```bash
if jj root &>/dev/null; then echo "jj"
elif git rev-parse --show-toplevel &>/dev/null; then echo "git"
else echo "none"
fi
```
## Command Mappings
| Operation | git | jj |
|-----------|-----|-----|
| Status | `git status` | `jj status` |
| Log | `git log` | `jj log` |
| Diff | `git diff` | `jj diff` |
| Commit | `git commit` | `jj commit` / `jj describe` |
| Branch list | `git branch` | `jj branch list` |
| New branch | `git checkout -b <name>` | `jj branch create <name>` |
| Push | `git push` | `jj git push` |
| Pull/Fetch | `git pull` / `git fetch` | `jj git fetch` |
| Rebase | `git rebase` | `jj rebase` |
## Usage
Before any VCS operation:
1. Run detection command
2. Use appropriate CLI based on result
3. If `none`, warn user directory is not version controlled
## Example Integration
```
User: Show me the git log
Agent: [Runs detection] -> Result: jj
Agent: [Runs `jj log` instead of `git log`]
```
## Colocated Repos
When both `.jj/` and `.git/` exist, the repo is "colocated":
- jj manages the working copy
- git is available for compatibility (GitHub, etc.)
- **Always prefer jj commands** in colocated repos