Build skills (Python) and apps (TypeScript) for agentOS — a local operating system for human-AI collaboration.
shapes/ Entity type definitions (YAML) — the ontology
skills-sdk/ Python SDK for building skills (data producers)
apps-sdk/ TypeScript SDK for building apps (data consumers)
docs/ Reference docs (shapes, skills, connections, auth, llm, data)
generate.py Codegen: shapes → typed code in SDK packages
agent-sdk CLI runner (no install needed)
Build a skill (Python data producer):
"""Curl — fetch any URL."""
from agentos import http, returns, provides, web_read
from lxml import html
@returns("webpage")
@provides(web_read)
def read_webpage(*, url: str, **params) -> dict:
"""Fetch a URL and return title + content."""
resp = http.get(url)
doc = html.fromstring(resp["body"])
title = doc.cssselect("title")
return {
"id": url,
"name": title[0].text_content() if title else url,
"url": url,
"content": resp["body"],
}That's it. A function with @returns, a readme with id + name, drop it in a skills directory, the engine picks it up.
Full walkthrough: docs/skills.md.
Shapes are agentOS's ISO standards. A message is a message whether it comes from iMessage, Gmail, or Claude Code. A book is a book whether it came from Goodreads or a library API. Skills and apps agree on the shape; the engine is generic.
./agent-sdk shapes # List all shapes
./agent-sdk shapes book # Inspect oneAuthoring a new shape:
- Write
agentos-sdk/shapes/<name>.yaml - Run
python generate.pyto update typed classes (_generated.py,shapes.ts) - Use it in a skill:
@returns("your_shape")+ return a conformant dict
The engine is shape-agnostic — shapes exist to document the ontology, drive codegen, and keep skills and apps honest. There's no engine restart, no graph seeding, no "push shape to graph" step.
Deep dive: docs/shapes.md — design principles, field types, also inheritance, _tag polymorphism, identity rules, review checklist.
Start here and follow the topic:
| Doc | What |
|---|---|
| docs/skills.md | Skill authoring — anatomy, decorators, SDK modules, naming, examples, common mistakes |
| docs/shapes.md | Shape ontology — format, field types, also chains, typed references, review checklist |
| docs/llm.md | LLM + agent workflows — llm.oneshot, llm.agent, structured output, parallel agents, checkpoints |
| docs/connections.md | Connections & auth — API keys, cookies, OAuth, SQLite, local data sources |
| docs/auth-flows.md | Implementing auth flows — discovery, cookie extraction, secret storage |
| docs/data.md | Skill state — cache vs data, sandbox storage, expressions |
| docs/principles.md | Shape design principles — higher-order philosophy |
| docs/reverse-engineering/ | 7-layer methodology for undocumented APIs |
- All I/O through SDK modules (
http,sql,shell,crypto,oauth) — never rawurllib,subprocess, etc. The sandbox blocks them. - Shape field names are camelCase (
startDate,postedBy). Python function names are snake_case. - Every tool has
@returns(shape)and accepts**params. - HTML parsing:
lxml+cssselect— no BeautifulSoup, no regex on HTML. - No Playwright — CDP to real browsers only.
- No runtime fallbacks — fix selectors, don't ship fallback chains.
Shapes are YAML. generate.py turns them into typed code for each SDK:
python generate.py # Python TypedDicts + TypeScript interfaces
python generate.py --lang python # Python only
python generate.py --from-api # load from running engine graph instead of YAML
python generate.py --lang rust --out-dir ./out # one-off export for other languagesPython goes to skills-sdk/agentos/_generated.py. TypeScript goes to apps-sdk/src/shapes.ts. Rust, Swift, and Go emitters are available via --out-dir.
./agent-sdk new-skill <name> # scaffold a new skill
./agent-sdk validate [dir] # check skill for errors
./agent-sdk shapes # list all shapes
./agent-sdk shapes <name> # inspect one shapeNo install needed — just clone and run.