Skip to content

Commit a22d3ec

Browse files
committed
feat(gateway,analytics): add level filter, max-lines, and search stats
1 parent b8599fb commit a22d3ec

30 files changed

+1180
-86
lines changed

.github/workflows/ci.yml

Lines changed: 15 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ env:
1212

1313
jobs:
1414
ci:
15-
name: CI
16-
runs-on: ubuntu-latest
15+
name: CI (${{ matrix.os }})
16+
runs-on: ${{ matrix.os }}
17+
strategy:
18+
matrix:
19+
os: [ubuntu-latest, macos-latest, windows-latest]
1720
steps:
1821
- uses: actions/checkout@v6
1922
- uses: dtolnay/rust-toolchain@stable
@@ -30,40 +33,6 @@ jobs:
3033
- name: Test
3134
run: cargo test --all-features
3235

33-
- name: Build
34-
run: cargo build --release
35-
36-
build:
37-
name: Build (${{ matrix.os }})
38-
runs-on: ${{ matrix.os }}
39-
strategy:
40-
matrix:
41-
os: [macos-latest, windows-latest]
42-
steps:
43-
- uses: actions/checkout@v6
44-
- uses: dtolnay/rust-toolchain@stable
45-
- uses: Swatinem/rust-cache@v2
46-
- run: cargo build --release
47-
48-
deny:
49-
name: cargo-deny
50-
runs-on: ubuntu-latest
51-
steps:
52-
- uses: actions/checkout@v6
53-
- uses: EmbarkStudios/cargo-deny-action@v2
54-
55-
coverage:
56-
name: Coverage
57-
runs-on: ubuntu-latest
58-
steps:
59-
- uses: actions/checkout@v6
60-
61-
- uses: dtolnay/rust-toolchain@stable
62-
with:
63-
components: llvm-tools-preview
64-
65-
- uses: Swatinem/rust-cache@v2
66-
6736
- name: Install cargo-llvm-cov
6837
uses: taiki-e/install-action@cargo-llvm-cov
6938

@@ -76,3 +45,13 @@ jobs:
7645
fail_ci_if_error: false
7746
files: lcov.info
7847
token: ${{ secrets.CODECOV_TOKEN }}
48+
49+
- name: Build
50+
run: cargo build --release
51+
52+
deny:
53+
name: cargo-deny
54+
runs-on: ubuntu-latest
55+
steps:
56+
- uses: actions/checkout@v6
57+
- uses: EmbarkStudios/cargo-deny-action@v2

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ repos:
3636
pass_filenames: false
3737
- id: cargo-test
3838
name: cargo test runner
39-
entry: cargo test --workspace
39+
entry: cargo test --workspace --quiet
4040
language: system
4141
pass_filenames: false
4242
env:

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.1.0] - 2026-01-30
11+
1012
### Added
1113

1214
- RFC-0000 defines skillc vision aligned with Agent Skills ecosystem (WI-2026-01-25-001)
@@ -97,6 +99,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9799
- Document list command in README (WI-2026-01-30-011)
98100
- Integration tests for lint command (WI-2026-01-30-012)
99101
- Integration tests for list command (WI-2026-01-30-012)
102+
- `skc stats --group-by search` returns search query breakdown (WI-2026-01-30-013)
103+
- `skc outline --level <n>` filters headings by level (WI-2026-01-30-013)
104+
- `skc show --max-lines <n>` limits output lines (WI-2026-01-30-013)
105+
- `skc open --max-lines <n>` limits output lines (WI-2026-01-30-013)
100106

101107
### Changed
102108

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,17 @@ skc lint my-skill # Check for issues
7171
skc build my-skill --target cursor # Deploy to Cursor
7272

7373
# Reading (also available as MCP tools)
74-
skc outline my-skill
74+
skc outline my-skill # List all headings
75+
skc outline my-skill --level 2 # Only # and ## headings
7576
skc show my-skill --section "API Reference"
77+
skc show my-skill --section "API" --max-lines 50 # Truncate output
78+
skc open my-skill SKILL.md --max-lines 100 # Read first 100 lines
7679
skc search my-skill "borrow checker"
7780
skc sources my-skill --pattern "*.md"
7881

7982
# Analytics
8083
skc stats my-skill --group-by sections
84+
skc stats my-skill --group-by search # Most frequent search terms
8185
skc sync --dry-run
8286
```
8387

docs/INTRODUCTION.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@
4646
| `sync` | Merge local logs to global store |
4747
| `mcp` | Start MCP server for agent integration |
4848

49+
### Common Options
50+
51+
| Command | Option | Description |
52+
| --------- | ------------- | ----------------------------------------------------------------- |
53+
| `outline` | `--level <n>` | Filter to headings ≤ level n (1-6) |
54+
| `show` | `--max-lines` | Truncate output to first n lines |
55+
| `open` | `--max-lines` | Truncate output to first n lines |
56+
| `stats` | `--group-by` | Aggregate by: sections, files, commands, projects, errors, search |
57+
4958
## Two Interfaces
5059

5160
| Interface | For | Example |

docs/rfc/RFC-0002.md

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- GENERATED: do not edit. Source: RFC-0002 -->
2-
<!-- SIGNATURE: sha256:9dbea24c76af1b5f57cd8d00094575f5ba0407cf77859614328f10fadf5fda73 -->
2+
<!-- SIGNATURE: sha256:6e0326ca0e8f85f836e2d94e2ec91bc8131e692946ed75d69e9e71635c74c16d -->
33

44
# RFC-0002: Gateway Protocol
55

@@ -33,10 +33,18 @@ See [RFC-0007:C-COMMANDS](../rfc/RFC-0007.md#rfc-0007c-commands) for the complet
3333

3434
### [RFC-0002:C-OUTLINE] Outline Command (Normative) <a id="rfc-0002c-outline"></a>
3535

36-
**Syntax:** `skc outline <skill>`
36+
**Syntax:** `skc outline <skill> [--level <n>]`
3737

3838
The outline command MUST scan all `.md` files in the skill's source directory and extract headings.
3939

40+
**Options:**
41+
42+
| Option | Description |
43+
|--------|-------------|
44+
| `--level <n>` | Maximum heading level to include (1-6, default: unlimited) |
45+
46+
When `--level` is provided, the command MUST only output headings with level ≤ n. For example, `--level 2` shows only `#` and `##` headings.
47+
4048
**Output format:**
4149
The command MUST output a structured list of headings with:
4250
- Heading level (1-6)
@@ -59,14 +67,35 @@ references/advanced.md
5967
## Performance
6068
```
6169

70+
With `--level 2`:
71+
```
72+
SKILL.md
73+
# Skill Name
74+
## Getting Started
75+
## API Reference
76+
references/advanced.md
77+
# Advanced Topics
78+
## Performance
79+
```
80+
6281
*Since: v0.1.0*
6382

6483
### [RFC-0002:C-SHOW] Show Command (Normative) <a id="rfc-0002c-show"></a>
6584

66-
**Syntax:** `skc show <skill> --section "<heading>" [--file <path>]`
85+
**Syntax:** `skc show <skill> --section "<heading>" [--file <path>] [--max-lines <n>]`
6786

6887
The show command MUST locate the specified heading and return its content.
6988

89+
**Options:**
90+
91+
| Option | Description |
92+
|--------|-------------|
93+
| `--file <path>` | Limit search to specific file |
94+
| `--max-lines <n>` | Maximum lines to return (default: unlimited) |
95+
96+
When `--max-lines` is provided, the command MUST truncate output to the first n lines. If content is truncated, the command MUST append a line:
97+
`... (N more lines)`
98+
7099
**Heading matching:**
71100
- Matching MUST be case-insensitive
72101
- Leading/trailing whitespace MUST be trimmed
@@ -87,17 +116,26 @@ If no heading matches, the command MUST exit with a non-zero status and a clear
87116

88117
### [RFC-0002:C-OPEN] Open Command (Normative) <a id="rfc-0002c-open"></a>
89118

90-
**Syntax:** `skc open <skill> <path>`
119+
**Syntax:** `skc open <skill> <path> [--max-lines <n>]`
91120

92121
The open command MUST return the contents of the specified file.
93122

123+
**Options:**
124+
125+
| Option | Description |
126+
|--------|-------------|
127+
| `--max-lines <n>` | Maximum lines to return (default: unlimited) |
128+
129+
When `--max-lines` is provided, the command MUST truncate output to the first n lines. If content is truncated, the command MUST append a line:
130+
`... (N more lines)`
131+
94132
**Path validation:**
95133
- The path MUST be relative to the skill source root
96134
- The path MUST NOT contain `..` sequences that escape the skill root
97135
- The path MUST refer to a file (not a directory)
98136

99137
**Content:**
100-
The command MUST return the file contents as-is without transformation.
138+
The command MUST return the file contents as-is without transformation (except for `--max-lines` truncation).
101139

102140
**File type:**
103141
The `open` command is NOT restricted to `.md` files. It can retrieve any file within the skill source directory. This enables retrieval of search results from non-`.md` files (e.g., `.txt`).

docs/rfc/RFC-0003.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- GENERATED: do not edit. Source: RFC-0003 -->
2-
<!-- SIGNATURE: sha256:00cfeef18895af0a4c45d82115ab4c8825be93efd32e7236af9c05f416e162e1 -->
2+
<!-- SIGNATURE: sha256:cc1e7b9921e547461a951786114753590a73a272505843f392ae0bbafba0c666 -->
33

44
# RFC-0003: Usage Analytics
55

@@ -53,6 +53,9 @@ Returns access counts grouped by calling directory (CWD). Each entry includes th
5353
**`errors`** — Failed lookups
5454
Returns a list of failed access attempts. Each entry includes the requested target, command type, error message, and count.
5555

56+
**`search`** — Search query breakdown
57+
Returns a list of search queries ordered by frequency (descending). Ties MUST be ordered by query text ascending. Each entry includes the query string and count. This enables understanding which search terms agents use most frequently.
58+
5659
The default query type MUST be `summary`.
5760

5861
*Since: v0.1.0*
@@ -159,6 +162,15 @@ All analytics responses MUST conform to a JSON schema for interoperability with
159162
]
160163
```
161164

165+
`search`:
166+
```json
167+
[
168+
{"query": "authentication", "count": 25},
169+
{"query": "error handling", "count": 18},
170+
{"query": "api", "count": 12}
171+
]
172+
```
173+
162174
The JSON output MUST be valid JSON. Field order is not significant.
163175

164176
*Since: v0.1.0*

docs/rfc/RFC-0007.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- GENERATED: do not edit. Source: RFC-0007 -->
2-
<!-- SIGNATURE: sha256:7e669328d6aa6f150574847e1a8d71da72e269872abaaea1b674fe7dd4723ca6 -->
2+
<!-- SIGNATURE: sha256:5fff06d3900ec8ee5d2b6a2e5b002776ca87fceddec447166e6c73bdff566023 -->
33

44
# RFC-0007: CLI Reference
55

@@ -113,6 +113,7 @@ Compiles to SSOT location (`.skillc/runtime/` for local sources, `~/.skillc/runt
113113
| Parameter | Type | Required | Default | Description |
114114
|-----------|------|----------|---------|-------------|
115115
| `skill` | string | yes || Skill name or path |
116+
| `level` | number | no | unlimited | Maximum heading level (1-6) |
116117

117118
### show
118119

@@ -121,13 +122,15 @@ Compiles to SSOT location (`.skillc/runtime/` for local sources, `~/.skillc/runt
121122
| `skill` | string | yes || Skill name or path |
122123
| `section` | string | yes || Section heading to retrieve |
123124
| `file` | string | no || Limit search to specific file |
125+
| `max_lines` | number | no | unlimited | Maximum lines to return |
124126

125127
### open
126128

127129
| Parameter | Type | Required | Default | Description |
128130
|-----------|------|----------|---------|-------------|
129131
| `skill` | string | yes || Skill name or path |
130132
| `path` | string | yes || Relative path within skill |
133+
| `max_lines` | number | no | unlimited | Maximum lines to return |
131134

132135
### sources
133136

@@ -152,7 +155,7 @@ Compiles to SSOT location (`.skillc/runtime/` for local sources, `~/.skillc/runt
152155
| Parameter | Type | Required | Default | Description |
153156
|-----------|------|----------|---------|-------------|
154157
| `skill` | string | yes || Skill name or path |
155-
| `group_by` | string | no | summary | Aggregation dimension: `files`, `sections`, `commands`, `projects`, `errors` |
158+
| `group_by` | string | no | summary | Aggregation dimension: `summary`, `files`, `sections`, `commands`, `projects`, `errors`, `search` |
156159
| `since` | string | no || Include accesses on or after (ISO 8601) |
157160
| `until` | string | no || Include accesses on or before (ISO 8601) |
158161
| `project` | string[] | no || Filter by project directory |

gov/releases.toml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
[[releases]]
2+
version = "0.1.0"
3+
date = "2026-01-30"
4+
refs = [
5+
"WI-2026-01-25-001",
6+
"WI-2026-01-25-002",
7+
"WI-2026-01-26-001",
8+
"WI-2026-01-26-002",
9+
"WI-2026-01-26-003",
10+
"WI-2026-01-27-001",
11+
"WI-2026-01-28-001",
12+
"WI-2026-01-28-002",
13+
"WI-2026-01-29-001",
14+
"WI-2026-01-29-002",
15+
"WI-2026-01-29-003",
16+
"WI-2026-01-29-004",
17+
"WI-2026-01-29-005",
18+
"WI-2026-01-29-006",
19+
"WI-2026-01-29-007",
20+
"WI-2026-01-29-008",
21+
"WI-2026-01-29-009",
22+
"WI-2026-01-29-010",
23+
"WI-2026-01-29-011",
24+
"WI-2026-01-29-012",
25+
"WI-2026-01-29-013",
26+
"WI-2026-01-29-014",
27+
"WI-2026-01-29-015",
28+
"WI-2026-01-29-016",
29+
"WI-2026-01-29-017",
30+
"WI-2026-01-29-018",
31+
"WI-2026-01-29-019",
32+
"WI-2026-01-29-020",
33+
"WI-2026-01-29-021",
34+
"WI-2026-01-29-022",
35+
"WI-2026-01-29-023",
36+
"WI-2026-01-29-024",
37+
"WI-2026-01-29-025",
38+
"WI-2026-01-29-026",
39+
"WI-2026-01-29-027",
40+
"WI-2026-01-30-001",
41+
"WI-2026-01-30-002",
42+
"WI-2026-01-30-003",
43+
"WI-2026-01-30-004",
44+
"WI-2026-01-30-005",
45+
"WI-2026-01-30-006",
46+
"WI-2026-01-30-007",
47+
"WI-2026-01-30-008",
48+
"WI-2026-01-30-009",
49+
"WI-2026-01-30-010",
50+
"WI-2026-01-30-011",
51+
"WI-2026-01-30-012",
52+
"WI-2026-01-30-013",
53+
]

gov/rfc/RFC-0002/clauses/C-OPEN.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
"title": "Open Command",
44
"kind": "normative",
55
"status": "active",
6-
"text": "**Syntax:** `skc open <skill> <path>`\n\nThe open command MUST return the contents of the specified file.\n\n**Path validation:**\n- The path MUST be relative to the skill source root\n- The path MUST NOT contain `..` sequences that escape the skill root\n- The path MUST refer to a file (not a directory)\n\n**Content:**\nThe command MUST return the file contents as-is without transformation.\n\n**File type:**\nThe `open` command is NOT restricted to `.md` files. It can retrieve any file within the skill source directory. This enables retrieval of search results from non-`.md` files (e.g., `.txt`).\n\n**Path safety:**\nThe command MUST reject any path that would resolve outside the skill source directory after canonicalization. See [[RFC-0005:C-CODES]] for error E012.\n\n**No match:**\nIf the file does not exist, the command MUST exit with error E021 per [[RFC-0005:C-CODES]].",
6+
"text": "**Syntax:** `skc open <skill> <path> [--max-lines <n>]`\n\nThe open command MUST return the contents of the specified file.\n\n**Options:**\n\n| Option | Description |\n|--------|-------------|\n| `--max-lines <n>` | Maximum lines to return (default: unlimited) |\n\nWhen `--max-lines` is provided, the command MUST truncate output to the first n lines. If content is truncated, the command MUST append a line:\n`... (N more lines)`\n\n**Path validation:**\n- The path MUST be relative to the skill source root\n- The path MUST NOT contain `..` sequences that escape the skill root\n- The path MUST refer to a file (not a directory)\n\n**Content:**\nThe command MUST return the file contents as-is without transformation (except for `--max-lines` truncation).\n\n**File type:**\nThe `open` command is NOT restricted to `.md` files. It can retrieve any file within the skill source directory. This enables retrieval of search results from non-`.md` files (e.g., `.txt`).\n\n**Path safety:**\nThe command MUST reject any path that would resolve outside the skill source directory after canonicalization. See [[RFC-0005:C-CODES]] for error E012.\n\n**No match:**\nIf the file does not exist, the command MUST exit with error E021 per [[RFC-0005:C-CODES]].",
77
"since": "0.1.0"
88
}

0 commit comments

Comments
 (0)