A single Cloudflare Worker serving both:
- Hono API under
/api/* - Vite React SPA through Cloudflare static assets
The stack uses Cloudflare Workers, D1, R2, Drizzle ORM, Hono, React, Vite, Tailwind CSS, shadcn-style UI components, TypeScript, Turborepo, pnpm, and Zod schemas.
apps/skillpack/ # Cloudflare Worker + Vite React SPA deployment unit
client/ # Vite React SPA
server/ # Hono app, Worker entrypoint, D1 schema
migrations/ # D1 migrations
packages/core/ # shared Skillpack primitives and Zod value schemas
packages/contracts/ # frontend/backend API request/response contracts
packages/typescript-config/ # shared TypeScript configs
pnpm install
pnpm dev
pnpm typecheck
pnpm test
pnpm buildFor manual browser smoke testing against the local app, see Local Browser Testing.
The Deploy to Cloudflare flow reads apps/skillpack/wrangler.jsonc, provisions
D1 and R2 bindings, prompts for required secrets, and connects the created
repository to Workers Builds for automatic deployments.
Skillpack uses Better Auth. GitHub is the primary sign-in provider, and the same GitHub OAuth App credentials are reused for authenticated public GitHub Origin reads. A generic OIDC provider can be enabled as an optional fallback; when OIDC vars are absent, the OIDC login button is hidden. Email/password sign-in is enabled for pre-provisioned accounts, while public signup is disabled.
For local development:
cp apps/skillpack/.dev.vars.example apps/skillpack/.dev.varsSet BETTER_AUTH_SECRET, GITHUB_CLIENT_ID, and GITHUB_CLIENT_SECRET in
.dev.vars. Register this redirect URI with your GitHub OAuth App:
http://localhost:5173/api/auth/callback/github
Optionally set OIDC_CLIENT_ID and OIDC_DISCOVERY_URL to enable fallback
OIDC login. Register this redirect URI with your OIDC provider:
http://localhost:5173/api/auth/oauth2/callback/oidc
Use a GitHub OAuth App for GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET, not a
personal access token. Those same values also raise GitHub API rate limits for
public GitHub-origin discovery and fork reads.
For now, Skillpack trusts the configured browser sign-in providers for same-email account linking while keeping Better Auth's email-verified checks. This is a temporary v1 shortcut; a formal account linking flow should replace it before adding more login providers.
Skillpack also acts as an OAuth Provider for agent-facing Skill Delivery. MCP clients and extensions should discover:
/.well-known/oauth-authorization-server
/.well-known/oauth-protected-resource
Public clients should use authorization code with PKCE, dynamic client
registration, and the skills:read scope. The OAuth resource/audience is the
Skillpack base URL, not a transport-specific URL such as /mcp.
For deployed environments, set secrets with Wrangler:
pnpm --filter @skillpack/app exec wrangler secret put BETTER_AUTH_SECRET
pnpm --filter @skillpack/app exec wrangler secret put GITHUB_CLIENT_ID
pnpm --filter @skillpack/app exec wrangler secret put GITHUB_CLIENT_SECRET
pnpm --filter @skillpack/app exec wrangler secret put OIDC_CLIENT_ID
pnpm --filter @skillpack/app exec wrangler secret put OIDC_DISCOVERY_URLGITHUB_CLIENT_ID, OIDC_CLIENT_ID, and OIDC_DISCOVERY_URL are not strictly
secret, but they are deployment-instance values. Keeping them in Cloudflare
rather than tracked wrangler.jsonc keeps the open source config reusable.
Register the deployed GitHub redirect URI with the same callback path:
https://<your-domain>/api/auth/callback/github
If OIDC is enabled, register the deployed OIDC redirect URI too:
https://<your-domain>/api/auth/oauth2/callback/oidc
apps/skillpack/wrangler.jsonc is committed as a reusable deployment template.
It declares the Worker entrypoint, static assets, D1 binding, R2 binding, and
required secrets. Instance-specific values such as OAuth credentials and custom
domains should be configured in Cloudflare.
For manual deployments, create resources:
pnpm --filter @skillpack/app exec wrangler d1 create skillpack
pnpm --filter @skillpack/app exec wrangler r2 bucket create skillpack-objectsFor a manual production instance, copy the generated D1 database_id into your
instance's apps/skillpack/wrangler.jsonc.
Apply migrations:
pnpm db:migrate:local
pnpm db:migrate:remoteThe current development migration resets Managed Skill tables to the Managed Skill model and drops old skill rows. Auth tables are not reset.
Seed local development data while pnpm dev is running:
pnpm db:seed:localThe seed command upserts and authenticates this local-only account before creating the example skills:
Email: dev@skillpack.local
Password: skillpack-dev
Deploy:
pnpm deployGET /api/health
POST /mcp
GET /api/v1/skills
GET /api/v1/skills/:skillName
GET /api/v1/skills/:skillName?version=
GET /api/v1/skills/:skillName/versions
GET /api/v1/skills/:skillName/resources?version=&path=
GET /api/v1/skills/:skillName/resources/raw?version=&path=
POST /api/v1/skills
POST /api/v1/skills/fork
PATCH /api/v1/skills/:skillName
POST /api/v1/skills/:skillName/versions/:versionNumber/restore
DELETE /api/v1/skills/:skillName
Create a skill:
curl -X POST http://localhost:5173/api/v1/skills \
-H 'content-type: application/json' \
-d '{
"name": "api-skill-demo",
"description": "Demo API-backed skill",
"versionLabel": "first draft",
"content": "# Demo Skill\n\nUse this skill when validating API-backed skills.",
"resources": [
{
"path": "references/demo.md",
"mediaType": "text/markdown; charset=utf-8",
"content": "# Demo Resource\n\nExtra context loaded on demand."
},
{
"path": "scripts/demo.py",
"mediaType": "text/x-python; charset=utf-8",
"content": "print('hello from a skill resource')\n"
}
]
}'Created Skillpack-managed skills are resolved by Skill Name in public APIs:
/api/v1/skills/demo
Skillpack exposes a remote MCP endpoint at /mcp for authenticated agents.
Call it with an OAuth Bearer token that has skills:read.
The MCP server exposes:
list_skills— list the authenticated user's Managed Skill catalog with SEP-2640skill://{skillName}/SKILL.mdlocations.read_skill— read a SkillpackSKILL.mdactivation payload by Skill Name.create_skillandupdate_skill— create and patch Managed Skills when the token hasskills:write.- MCP resources — read
skill://index.json,skill://{skillName}/SKILL.md, and attached resources such asskill://{skillName}/references/guide.md.
Agents use read_skill for Skillpack Skill Names and MCP resources/read for standard resource reads.