Skip to content

Commit 214ce57

Browse files
authored
Implement Agent Skills discovery with progressive disclosure (#182)
1 parent 5633e5b commit 214ce57

14 files changed

Lines changed: 921 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
coding-context
33
coding-context-cli
44
*.test
5+
6+
# Test workspaces
7+
examples/test-workspace/

examples/agents/skills/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Agent Skills Examples
2+
3+
This directory contains example skills that demonstrate the Agent Skills format.
4+
5+
## What are Agent Skills?
6+
7+
Agent Skills are a lightweight, open format for extending AI agent capabilities with specialized knowledge and workflows. Each skill is a folder containing a `SKILL.md` file with metadata and instructions.
8+
9+
## Skills in this directory
10+
11+
### pdf-processing
12+
13+
Extract text and tables from PDF files, fill PDF forms, and merge multiple PDFs.
14+
15+
```bash
16+
coding-context -C examples/test-workspace your-task
17+
```
18+
19+
### data-analysis
20+
21+
Analyze datasets, generate charts, and create summary reports for CSV, Excel, and other tabular data formats.
22+
23+
## Skill Structure
24+
25+
Each skill folder contains:
26+
27+
```
28+
skill-name/
29+
├── SKILL.md # Required: instructions + metadata
30+
├── scripts/ # Optional: executable code
31+
├── references/ # Optional: documentation
32+
└── assets/ # Optional: templates, resources
33+
```
34+
35+
## Required Frontmatter
36+
37+
The `SKILL.md` file must contain YAML frontmatter with at least:
38+
39+
- `name`: A unique identifier (1-64 characters, lowercase alphanumeric and hyphens only)
40+
- `description`: What the skill does and when to use it (1-1024 characters)
41+
42+
Example:
43+
44+
```yaml
45+
---
46+
name: pdf-processing
47+
description: Extract text and tables from PDF files, fill forms, merge documents.
48+
---
49+
```
50+
51+
## Optional Frontmatter
52+
53+
- `license`: License name or reference
54+
- `compatibility`: Environment requirements
55+
- `metadata`: Additional key-value pairs
56+
- `allowed-tools`: Pre-approved tools (experimental)
57+
58+
## Progressive Disclosure
59+
60+
Skills use progressive disclosure for efficient context management:
61+
62+
1. **Discovery**: At startup, only the `name` and `description` are loaded
63+
2. **Activation**: When relevant, the agent loads the full `SKILL.md` content
64+
3. **Execution**: Scripts and resources are loaded as needed
65+
66+
## Selectors
67+
68+
Skills can be filtered using selectors in their frontmatter, just like rules:
69+
70+
```yaml
71+
---
72+
name: dev-skill
73+
description: A skill for development environments
74+
env: development
75+
---
76+
```
77+
78+
Then use with:
79+
80+
```bash
81+
coding-context -s env=development your-task
82+
```
83+
84+
Skills without the selector key are included by default (OR logic).
85+
86+
## Testing
87+
88+
To see skills in action:
89+
90+
```bash
91+
# Navigate to the test workspace
92+
cd examples/test-workspace
93+
94+
# Run a simple task and see discovered skills
95+
coding-context simple
96+
```
97+
98+
The output will include an `<available_skills>` section with skill metadata.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
name: data-analysis
3+
description: Analyze datasets, generate charts, and create summary reports. Use when the user needs to work with CSV, Excel, or other tabular data formats for analysis or visualization.
4+
---
5+
6+
# Data Analysis
7+
8+
## When to use this skill
9+
Use this skill when the user needs to:
10+
- Analyze CSV or Excel files
11+
- Generate charts and visualizations
12+
- Calculate statistics and summaries
13+
- Clean and transform data
14+
15+
## How to analyze data
16+
1. Use pandas for data analysis:
17+
```python
18+
import pandas as pd
19+
df = pd.read_csv('data.csv')
20+
summary = df.describe()
21+
```
22+
23+
## How to create visualizations
24+
1. Use matplotlib or seaborn for charts:
25+
```python
26+
import matplotlib.pyplot as plt
27+
df.plot(kind='bar')
28+
plt.savefig('chart.png')
29+
```
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
---
2+
name: pdf-processing
3+
description: Extract text and tables from PDF files, fill PDF forms, and merge multiple PDFs. Use when working with PDF documents or when the user mentions PDFs, forms, or document extraction.
4+
license: Apache-2.0
5+
metadata:
6+
author: example-org
7+
version: "1.0"
8+
---
9+
10+
# PDF Processing
11+
12+
## When to use this skill
13+
Use this skill when the user needs to work with PDF files, including:
14+
- Extracting text or tables from PDF documents
15+
- Filling out PDF forms programmatically
16+
- Merging multiple PDF files into one
17+
- Splitting PDF files into separate documents
18+
19+
## How to extract text
20+
1. Use pdfplumber for text extraction:
21+
```python
22+
import pdfplumber
23+
with pdfplumber.open('document.pdf') as pdf:
24+
text = pdf.pages[0].extract_text()
25+
```
26+
27+
## How to fill forms
28+
1. Use PyPDF2 to fill form fields:
29+
```python
30+
from PyPDF2 import PdfReader, PdfWriter
31+
reader = PdfReader('form.pdf')
32+
writer = PdfWriter()
33+
# Fill fields here
34+
```
35+
36+
## How to merge documents
37+
See [the reference guide](references/REFERENCE.md) for details.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# PDF Processing Reference Guide
2+
3+
## Supported Libraries
4+
5+
### pdfplumber
6+
- Text extraction
7+
- Table detection and extraction
8+
- Image extraction
9+
- Comprehensive metadata access
10+
11+
### PyPDF2
12+
- Form field manipulation
13+
- PDF merging and splitting
14+
- Encryption and decryption
15+
- Rotation and cropping
16+
17+
## Detailed Examples
18+
19+
### Extract Tables
20+
21+
```python
22+
import pdfplumber
23+
24+
with pdfplumber.open('document.pdf') as pdf:
25+
for page in pdf.pages:
26+
tables = page.extract_tables()
27+
for table in tables:
28+
# Process table data
29+
print(table)
30+
```
31+
32+
### Fill PDF Forms
33+
34+
```python
35+
from PyPDF2 import PdfReader, PdfWriter
36+
37+
reader = PdfReader('form.pdf')
38+
writer = PdfWriter()
39+
40+
# Get the first page
41+
page = reader.pages[0]
42+
43+
# Update form fields
44+
writer.add_page(page)
45+
writer.update_page_form_field_values(
46+
writer.pages[0],
47+
{"field_name": "value"}
48+
)
49+
50+
# Save the filled form
51+
with open('filled_form.pdf', 'wb') as output_file:
52+
writer.write(output_file)
53+
```
54+
55+
### Merge PDFs
56+
57+
```python
58+
from PyPDF2 import PdfMerger
59+
60+
merger = PdfMerger()
61+
62+
# Add multiple PDFs
63+
merger.append('file1.pdf')
64+
merger.append('file2.pdf')
65+
merger.append('file3.pdf')
66+
67+
# Write merged PDF
68+
merger.write('merged.pdf')
69+
merger.close()
70+
```
71+
72+
## Performance Considerations
73+
74+
- For large PDFs, process pages incrementally
75+
- Use caching for frequently accessed documents
76+
- Consider parallel processing for batch operations
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Extract text from a PDF file.
4+
5+
Usage:
6+
extract.py <input_pdf> [output_txt]
7+
"""
8+
9+
import sys
10+
import pdfplumber
11+
12+
def extract_text(pdf_path, output_path=None):
13+
"""Extract text from all pages of a PDF."""
14+
text_content = []
15+
16+
try:
17+
with pdfplumber.open(pdf_path) as pdf:
18+
for i, page in enumerate(pdf.pages, 1):
19+
print(f"Processing page {i}/{len(pdf.pages)}...", file=sys.stderr)
20+
text = page.extract_text()
21+
if text:
22+
text_content.append(f"--- Page {i} ---\n{text}\n")
23+
24+
result = '\n'.join(text_content)
25+
26+
if output_path:
27+
with open(output_path, 'w', encoding='utf-8') as f:
28+
f.write(result)
29+
print(f"Text extracted to {output_path}", file=sys.stderr)
30+
else:
31+
print(result)
32+
33+
except Exception as e:
34+
print(f"Error: {e}", file=sys.stderr)
35+
sys.exit(1)
36+
37+
if __name__ == '__main__':
38+
if len(sys.argv) < 2:
39+
print(__doc__, file=sys.stderr)
40+
sys.exit(1)
41+
42+
input_pdf = sys.argv[1]
43+
output_txt = sys.argv[2] if len(sys.argv) > 2 else None
44+
45+
extract_text(input_pdf, output_txt)

main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,17 @@ func main() {
166166
fmt.Println("---")
167167
}
168168

169+
// Output available skills metadata (progressive disclosure)
170+
if len(result.Skills.Skills) > 0 {
171+
skillsXML, err := result.Skills.AsXML()
172+
if err != nil {
173+
logger.Error("Failed to encode skills as XML", "error", err)
174+
os.Exit(1)
175+
}
176+
fmt.Println(skillsXML)
177+
fmt.Println()
178+
}
179+
169180
// Output the combined prompt (rules + task)
170181
fmt.Println(result.Prompt)
171182
}

0 commit comments

Comments
 (0)