Hadrian is experimental alpha software. Do not use in production.
Hadrian
Features

Skills

Package instructions and bundled files that the model can auto-invoke or users can trigger with a slash command.

Skills extend what the model can do by packaging reusable instructions as portable units. Each skill is a SKILL.md file plus optional bundled scripts, references, and assets. You author skills with the Agent Skills SKILL.md format, and manage them through an OpenAI-compatible /v1/skills API — skills are immutable and versioned, with a default_version/latest_version pointer, just like the OpenAI Skills API (plus Hadrian's multi-tenant ownership extension).

What a skill looks like

Every skill is a directory with at minimum a SKILL.md file containing YAML frontmatter and Markdown instructions:

---
name: pdf-processing
description: Extract PDF text, fill forms, merge files. Use when handling PDFs.
allowed-tools: Bash(python:*) Read
---

# PDF Processing

## When to use this skill

Use this skill when the user needs to work with PDF files.

## How to extract text

1. Run `scripts/extract.py <input.pdf>`
2. Parse the output into a structured summary.

Optional bundled files (kept alongside the SKILL.md) become available to the model on demand:

pdf-processing/
├── SKILL.md            # Required: instructions + metadata
├── scripts/            # Optional: executable code
│   └── extract.py
├── references/         # Optional: docs
│   └── REFERENCE.md
└── assets/             # Optional: templates, data files
    └── template.md

Frontmatter fields

FieldRequiredDescription
nameYesUnique per owner. 1–64 lowercase ASCII alphanumerics or hyphens, no leading/trailing/consecutive hyphens.
descriptionYes1–1024 chars. Drives model invocation — front-load trigger phrases ("Use when…", "when the user mentions…").
user_invocableNoDefault true. Set to false to hide from the / menu; useful for background-knowledge skills the model auto-loads.
disable_model_invocationNoDefault false. Set to true for skills that should only run when the user explicitly picks them.
allowed_toolsNoSpace-separated list (or YAML array) of tool patterns the skill may use.
argument_hintNoShown during / autocomplete, e.g. [issue-number].
metadataNoArbitrary key/value pairs preserved verbatim.

Any additional keys are preserved in frontmatter_extra so unknown spec-adjacent fields (for third-party agents) round-trip cleanly.

How the model invokes a skill

Hadrian registers a single Skill function tool with the model whenever one or more skills are enabled for the current session. The tool's description lists each enabled skill by name and description — the model matches user intent against those entries and calls Skill({command: "<name>"}) to load the full instructions.

The executor runs in the browser:

  1. First callSkill({command: "<name>"}) returns the skill's SKILL.md body plus a manifest of bundled files.
  2. Follow-up callsSkill({command: "<name>", file: "<path>"}) returns the contents of a specific bundled file referenced in the SKILL.md.

This matches Claude Code's progressive-disclosure model: the main instructions enter context once; reference files load only when needed.

Skills are not injected into the system prompt. The directory lives in the Skill tool's description, so unused skills don't pollute every request.

Ownership & sharing

Like prompt templates, skills belong to one of four owners:

OwnerVisible to
userOnly the owning user.
projectAll members of the project.
teamAll members of the team.
organizationAll organization members, subject to RBAC rules on skill:list/read.

Chat surfaces all skills the current user can reach. In the admin UI, manage project skills from Project → Skills.

Managing skills via the API

Skills live under the OpenAI-compatible /v1/skills surface. IDs are prefixed strings (skill_…, version ids skillver_…) and timestamps are unix seconds.

Method & pathPurpose
POST /v1/skillsCreate a skill (publishes version 1).
GET /v1/skillsList skills for the current project / accessible owners.
GET /v1/skills/{id}Get a skill (with the default version's files).
POST /v1/skills/{id}Set the default version ({ "default_version": "2" }).
DELETE /v1/skills/{id}Delete a skill.
GET /v1/skills/{id}/contentDownload the default version as a zip bundle.
POST /v1/skills/{id}/versionsPublish a new immutable version.
GET /v1/skills/{id}/versionsList versions.
GET /v1/skills/{id}/versions/{version}Get a specific version.
DELETE /v1/skills/{id}/versions/{version}Delete a version.
GET /v1/skills/{id}/versions/{version}/contentDownload a specific version as zip.

Versioning

Skills are immutable — content never changes in place. To update a skill, publish a new version with POST /v1/skills/{id}/versions (pass "default": true to make it the new default, or repoint later with POST /v1/skills/{id}). The skill projection (name, description, files) always reflects the default version. Versions are numbered 1, 2, … and never reused; the default version cannot be deleted (set another default first).

Upload formats

Create and version-create accept either:

  • application/json — a { path, content } file array (Hadrian extension; what the chat UI sends). owner, name, and description may be supplied explicitly or sniffed from the SKILL.md frontmatter.
  • multipart/form-data — a directory of files[] parts, or a single zip part. owner_type/owner_id/name/description/default ride along as form fields.

GET …/content returns an application/zip bundle.

Ownership extension

OpenAI's skills are project-scoped; Hadrian keeps owner_type/owner_id (organization/team/project/user) as a documented extension. On create, omit owner to default to the API key's scope, or set it explicitly. List with ?owner_type=&owner_id= to scope to one owner, or omit both for everything the caller can access.

Referencing skills from the Responses API

Attach skills to a /v1/responses request via a skill_reference:

{ "type": "skill_reference", "skill_id": "skill_…", "version": "latest" }

skill_id accepts a prefixed id, a bare UUID, or the skill's name slug. version is a positive integer or "latest"; omit it for the default version.

Invoking a skill as a user

Two equivalent ways:

  • Slash command. Type /<skill-name> in the chat composer. A popover lists matching skills; press Enter or Tab to commit. The composer prefixes your message with a request to use that skill.
  • Skills button. Click the Skills icon in the chat toolbar to open the popover. Check a skill to enable it for the session — the model may then auto-invoke it when relevant.

Importing skills

Use the Skills button's + menu to import.

From GitHub

Paste a GitHub URL (e.g. https://github.com/anthropics/skills) or owner/repo. Hadrian walks the tree via the public GitHub Contents API, finds every directory containing a SKILL.md, and bundles the adjacent files. Preview the discovered skills and pick which to import.

The unauthenticated GitHub API allows 60 requests/hour. Hadrian caches directory listings in sessionStorage for 10 minutes to soften this, and surfaces the remaining quota in the import modal.

From the filesystem

Choose a folder via the file picker (browsers supporting <input webkitdirectory> — Chromium-based and Safari). Hadrian reads every file under directories containing a SKILL.md.

Binary files are rejected in v1 — skill contents are stored as UTF-8 text.

Configuration

Per-skill size and per-owner limits live under [limits.resource_limits] in hadrian.toml:

[limits.resource_limits]
# Maximum skills per owner (org/team/project/user). Default: 5000.
max_skills_per_owner = 5000

# Maximum total size of a skill's files in bytes (SKILL.md + bundled).
# Default: 512000 (500 KiB). Set to 0 for unlimited.
max_skill_bytes = 512_000

# Maximum immutable versions retained per skill. Default: 0 (unlimited).
max_skill_versions_per_skill = 0

The skill upload request body cap is separate, under [server]:

[server]
# Max request body for skill uploads (zip bundles / multipart). Default: 64 MiB.
skills_body_limit_bytes = 67_108_864

v1 limitations

  • Text-only files. Binary assets (images, PDFs) are rejected at the API boundary. Future work: base64 encoding or object-storage offload.
  • Scripts are read-only in chat. The chat UI's Skill tool can read scripts/ files but cannot execute them — there is no client-side sandbox. Skills that require script execution won't work end-to-end in the chat UI.
  • Two invocation paths. The chat UI's /<name> slash command and Skill tool are frontend-only. Separately, the Responses API resolves a skill_reference server-side and mounts the referenced version's files into the shell-tool sandbox (under /skills/<id>), where scripts can run if the configured runtime supports it.

On this page