Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
85dd4c9
Split Skippy by functional boundary
i386 Aug 8, 2026
48998f4
Rebuild llama patch queue by functional boundary
i386 Aug 8, 2026
e3733fc
Add explicit standard library includes to Skippy modules
i386 Aug 8, 2026
0779302
Add explicit tokenization limit dependency
i386 Aug 8, 2026
425b11d
Address Skippy queue review findings
i386 Aug 8, 2026
354ff23
Advertise Skippy chat feature support
i386 Aug 8, 2026
c3a297e
Fix split GGUF stage inventory discovery (#1199)
i386 Aug 8, 2026
ce4b27b
feat: pass reasoning effort through Skippy templates
i386 Aug 8, 2026
6c76c83
feat: advertise reasoning efforts in model listings
i386 Aug 9, 2026
5ff95a5
docs: require Skippy ABI inventories in PRs
i386 Aug 9, 2026
f7d7efa
docs: clarify Skippy ABI lockstep policy
i386 Aug 9, 2026
e4a5ed2
refactor: remove legacy Skippy chat ABI
i386 Aug 9, 2026
7e3d60b
fix: stop advertising reasoning effort values
i386 Aug 9, 2026
b498e45
fix: preserve Skippy no-thinking override
i386 Aug 9, 2026
f37fa82
docs: publish Skippy native API reference
i386 Aug 9, 2026
1f715f2
fix: address Skippy API doc review comments
i386 Aug 9, 2026
d75ec05
Split Skippy by functional boundary
i386 Aug 8, 2026
47eb1c4
Rebuild llama patch queue by functional boundary
i386 Aug 8, 2026
d0a20d6
Add explicit standard library includes to Skippy modules
i386 Aug 8, 2026
0927a4f
Add explicit tokenization limit dependency
i386 Aug 8, 2026
534a646
Address Skippy queue review findings
i386 Aug 8, 2026
82b00e9
Advertise Skippy chat feature support
i386 Aug 8, 2026
618e785
Fix split GGUF stage inventory discovery (#1199)
i386 Aug 8, 2026
0852cea
feat: pass reasoning effort through Skippy templates
i386 Aug 8, 2026
8884319
feat: advertise reasoning efforts in model listings
i386 Aug 9, 2026
fab39ff
docs: require Skippy ABI inventories in PRs
i386 Aug 9, 2026
eb2b865
docs: clarify Skippy ABI lockstep policy
i386 Aug 9, 2026
0fdc27c
refactor: remove legacy Skippy chat ABI
i386 Aug 9, 2026
bc64ab2
fix: stop advertising reasoning effort values
i386 Aug 9, 2026
38ac03a
fix: preserve Skippy no-thinking override
i386 Aug 9, 2026
e090829
Merge remote-tracking branch 'mesh/jd/fix-issue-986-reasoning-effort-…
i386 Aug 10, 2026
3c442dd
Merge remote-tracking branch 'mesh/jd/fix-issue-986-reasoning-effort-…
i386 Aug 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .agents/skills/llama-stage-patch-changes/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ Use this skill when changing the Skippy staged-runtime ABI carried in
- Do not preserve retired source include paths unless the task explicitly asks
for compatibility. Continue to version and mirror any binary ABI change.

## Native API documentation

- Treat Doxygen-style comments in `include/skippy.h` and
`include/skippy/*.h` as the source of truth for the public API reference.
Every public header and exported `skippy_*` function must have an adjacent
`@brief` describing what it is used for.
- When the public header surface changes, prepare the patched checkout and
regenerate the website reference before finishing the change:

```bash
scripts/prepare-llama.sh pinned
python3 scripts/generate-skippy-api-doc.py
python3 scripts/generate-skippy-api-doc.py --check
```

- Commit `website/src/docs/pages/skippy-api.md` alongside the native queue
change. The generated page must not be hand-edited, and its inventory must
include every public header and exported function in the prepared checkout.

## ABI PR documentation requirements

Every pull request that changes the Skippy ABI must include an explicit ABI
Expand Down
19 changes: 18 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,24 @@ implementation file.
for retired paths unless a task explicitly requires them. Binary ABI changes
still require the normal Skippy ABI version bump and synchronized Rust FFI
constants.

### Skippy native API documentation

- Treat Doxygen-style comments in `include/skippy.h` and
`include/skippy/*.h` as the source of truth for the public native API
reference. Document every public header and exported `skippy_*` function
beside its declaration with an `@brief` describing the capability it owns.
- After changing a public Skippy header or exported function, prepare the
patched native checkout and regenerate the website page:

```bash
scripts/prepare-llama.sh pinned
python3 scripts/generate-skippy-api-doc.py
python3 scripts/generate-skippy-api-doc.py --check
```

- Commit the regenerated `website/src/docs/pages/skippy-api.md` with the
native queue change. Do not hand-edit the generated page or let a native API
PR merge without updating the website reference.
## Workspace Crates

The workspace lives under `crates/`. The most important crates:
Expand Down
261 changes: 261 additions & 0 deletions scripts/generate-skippy-api-doc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
#!/usr/bin/env python3

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

ew

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

haha

"""Generate the website's Skippy native API reference from patched headers."""

from __future__ import annotations

import argparse
import re
import sys
from dataclasses import dataclass
from pathlib import Path


@dataclass(frozen=True)
class Function:
name: str
declaration: str
brief: str


@dataclass(frozen=True)
class Header:
name: str
brief: str
declarations: tuple[str, ...]
functions: tuple[Function, ...]


def normalize_declaration(declaration: str) -> str:
return re.sub(r"\s+", " ", declaration.strip())


def pretty_declaration(declaration: str) -> str:
declaration = normalize_declaration(declaration)
declaration = declaration.replace("(", "(\n ", 1)
declaration = declaration.replace(", ", ",\n ")
declaration = re.sub(r"\s+\);$", "\n);", declaration)
return declaration


def anchor_id(prefix: str, value: str) -> str:
slug = re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")
return f"skippy-{prefix}-{slug}"


def header_anchor(header: Header) -> str:
return anchor_id("header", header.name)


def function_anchor(function: Function) -> str:
return anchor_id("fn", function.name)


def comment_brief(comment: str) -> str:
lines = []
for line in comment.splitlines():
line = re.sub(r"^\s*\*/\s*$", "", line)
line = re.sub(r"^\s*/?\*+\s?", "", line)
line = re.sub(r"\s*\*/\s*$", "", line)
lines.append(line.strip())
normalized = "\n".join(lines)
match = re.search(r"@brief\s+(.+?)(?=\n@\w+|$)", normalized, re.DOTALL)
if match is None:
return ""
return re.sub(r"\s+", " ", match.group(1)).strip()


def parse_header(path: Path) -> Header:
text = path.read_text()
file_comment = re.search(r"/\*\*.*?@file.*?\*/", text, re.DOTALL)
if file_comment is None:
raise ValueError(f"missing file documentation in {path}")
brief = comment_brief(file_comment.group(0))
if not brief:
raise ValueError(f"missing @brief for {path}")

functions: list[Function] = []
function_pattern = re.compile(r"LLAMA_API\s+.*?;", re.DOTALL)
for match in function_pattern.finditer(text):
declaration = normalize_declaration(match.group(0))
name_match = re.search(r"\b(skippy_[a-zA-Z0-9_]+)\s*\(", declaration)
if name_match is None:
continue
preceding = text[: match.start()]
comments = list(re.finditer(r"/\*\*.*?\*/", preceding, re.DOTALL))
comment = comments[-1] if comments and not preceding[comments[-1].end():].strip() else None
function_brief = comment_brief(comment.group(0)) if comment else ""
if not function_brief:
raise ValueError(f"missing @brief for {name_match.group(1)} in {path}")
Comment thread
i386 marked this conversation as resolved.
functions.append(Function(name_match.group(1), declaration, function_brief))

declarations: list[str] = []
for match in re.finditer(r"^(?:struct|enum)\s+(skippy_[a-zA-Z0-9_]+)\s*(?:\{|;)", text, re.MULTILINE):
declarations.append(match.group(1))
for match in re.finditer(r"^#define\s+(SKIPPY_[A-Z0-9_]+)(?:[ \t]+(.+))?$", text, re.MULTILINE):
if match.group(1) == "SKIPPY_H" or match.group(1).endswith("_H"):
continue
value = (match.group(2) or "").strip()
declarations.append(f"{match.group(1)} = {value}" if value else match.group(1))
Comment thread
i386 marked this conversation as resolved.

return Header(path.name, brief, tuple(dict.fromkeys(declarations)), tuple(functions))


def render(headers: list[Header], include_dir: Path) -> str:
functions = [function for header in headers for function in header.functions]
lines = [
"---",
"title: Skippy native API",
"description: Generated reference for the capability-oriented Skippy C ABI.",
"---",
"",
"<!-- This file is generated by scripts/generate-skippy-api-doc.py. Do not edit it by hand. -->",
"",
"# Skippy native API",
"",
"This reference is generated from the patched llama.cpp public headers. It documents the native C ABI used by Skippy's Rust FFI layer and staged runtime. The ABI is experimental and versioned for lockstep native/Rust builds.",
"",
f"Current generated surface: **{len(headers)} headers** and **{len(functions)} exported functions**.",
"",
"## Quick navigation",
"",
'<nav class="skippy-api-quicknav" aria-label="Skippy API quick navigation" data-pagefind-ignore="all">',
' <a class="skippy-api-quicknav__item" href="#skippy-include-map"><span class="skippy-api-quicknav__number">01</span><strong>Headers</strong><small>Choose a capability</small></a>',
' <a class="skippy-api-quicknav__item" href="#skippy-function-index"><span class="skippy-api-quicknav__number">02</span><strong>Functions</strong><small>Jump to a symbol</small></a>',
' <a class="skippy-api-quicknav__item" href="#skippy-abi-conventions"><span class="skippy-api-quicknav__number">03</span><strong>ABI rules</strong><small>Ownership and buffers</small></a>',
' <a class="skippy-api-quicknav__item" href="#skippy-native-declarations"><span class="skippy-api-quicknav__number">04</span><strong>Types</strong><small>Enums and structs</small></a>',
"</nav>",
"",
'<div id="skippy-function-index" class="skippy-api-index" data-pagefind-ignore="all">',
' <div class="skippy-api-index__heading">',
' <p class="skippy-api-index__eyebrow">Symbol index</p>',
' <p class="skippy-api-index__hint">Select a function to jump directly to its native declaration.</p>',
" </div>",
' <div class="skippy-api-index__groups">',
]
for header in headers:
if not header.functions:
continue
lines.extend(
[
' <section class="skippy-api-index__group">',
f' <a class="skippy-api-index__group-title" href="#{header_anchor(header)}"><code>{header.name}</code><span>{len(header.functions)} functions</span></a>',
' <div class="skippy-api-index__functions">',
]
)
for function in header.functions:
lines.append(f' <a href="#{function_anchor(function)}"><code>{function.name}</code></a>')
lines.extend([" </div>", " </section>"])
lines.extend(
[
" </div>",
"</div>",
"",
'<a id="skippy-include-map"></a>',
"## Include map",
"",
"Include the umbrella header for the complete surface:",
"",
"```cpp",
"#include <skippy.h>",
"```",
"",
"Capability consumers can include a narrower header:",
"",
"| Header | Used for |",
"|---|---|",
]
)
for header in headers:
header_path = "include/skippy.h" if header.name == "skippy.h" else f"include/skippy/{header.name}"
lines.append(f"| `{header_path}` | {header.brief} |")

lines.extend(
[
"",
'<a id="skippy-abi-conventions"></a>',
"## ABI conventions",
"",
"- All exported functions use the `skippy_` prefix and return `skippy_status`, except direct discovery values and `void` cleanup functions.",
"- Handles are opaque C structs. Successful creators transfer ownership to the caller; the matching `*_free` function releases them.",
"- Buffer-writing functions use caller-provided pointers and capacities, returning the required size through an output parameter and `SKIPPY_STATUS_BUFFER_TOO_SMALL` when needed.",
"- Errors returned through `struct skippy_error ** out_error` are owned by the caller and must be released with `skippy_error_free`.",
"- Check `skippy_abi_version()` and `skippy_abi_features()` before using optional capabilities.",
"",
'<a id="skippy-exported-functions"></a>',
"## Exported functions",
"",
]
)
for header in headers:
if not header.functions:
continue
lines.extend([f'<a id="{header_anchor(header)}"></a>', f"### `{header.name}`", ""])
for function in header.functions:
lines.extend(
[
f'<a id="{function_anchor(function)}"></a>',
f"#### `{function.name}`",
"",
function.brief,
"",
"```cpp",
pretty_declaration(function.declaration),
"```",
"",
]
)
lines.extend(['<a class="skippy-api-backlink" href="#skippy-function-index">↩ Back to function index</a>', ""])

lines.extend([ '<a id="skippy-native-declarations"></a>', "## Native declarations", "", "The headers also define the following enums, structs, opaque handles, and ABI constants:", ""])
for header in headers:
if header.declarations:
lines.append(f"- `{header.name}`: {', '.join(f'`{item}`' for item in header.declarations)}")
lines.extend(
[
"",
"Source directory: `include/skippy/`. Regenerate this page after changing any public header or exported function.",
"",
]
)
return "\n".join(lines)


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
repo_root = Path(__file__).resolve().parents[1]
parser.add_argument(
"--include-dir",
type=Path,
default=repo_root / ".deps/llama.cpp/include/skippy",
help="prepared patched llama.cpp Skippy header directory",
)
parser.add_argument(
"--output",
type=Path,
default=repo_root / "website/src/docs/pages/skippy-api.md",
help="generated website Markdown path",
)
parser.add_argument("--check", action="store_true", help="fail if the generated output differs")
args = parser.parse_args()

if not args.include_dir.is_dir():
print(
f"Skippy headers not found at {args.include_dir}. Run scripts/prepare-llama.sh pinned first or pass --include-dir.",
file=sys.stderr,
)
return 2

paths = [args.include_dir.parent / "skippy.h", *sorted(args.include_dir.glob("*.h"))]
headers = [parse_header(path) for path in paths if path.exists()]
output = render(headers, args.include_dir)
if args.check:
current = args.output.read_text() if args.output.exists() else ""
return 0 if current == output else 1
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(output)
print(f"generated {args.output} from {len(headers)} headers and {sum(len(h.functions) for h in headers)} functions")
return 0


if __name__ == "__main__":
raise SystemExit(main())
Loading
Loading