
Security News
GPT-6 Astra Attempts Supply Chain Attacks Against Open Source Maintainers in Testing
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.
service-plane
Advanced tools
Ability-first Service Plane primitives for schema-backed Cap'n Web RPC, STS capability tokens, OpenAPI, and MCP projections.
Ability-first service APIs for TypeScript services.
service-plane gives independently deployed services one shared model:
Service authors define abilities. Hono stays the HTTP shell for middleware, discovery, and adapter routes.
The library is written against web-standard globals only (crypto.subtle, fetch/Request, TextEncoder, timers) and runs on Node 20+, Cloudflare Workers, Deno, and Bun. That claim is exercised in CI on every push: the full test suite runs on Node 20/22/24 and inside real workerd isolates (via @cloudflare/vitest-pool-workers), and a bundled smoke — HTTP-batch end to end, streaming over a session transport, token verification accepting and rejecting — runs on Deno and Bun.
npm install service-plane hono @hono/capnweb capnweb
Ability schemas come from a validation library you choose; service-plane does not bundle or require any particular one. Add whichever you already use — anything implementing Standard Schema and its Standard JSON Schema companion:
npm install arktype # or zod, or @vinejs/vine, or valibot + @valibot/to-json-schema
See Choosing A Validation Library for versions and the one wrapper Valibot needs. Code samples in this README and the docs use Zod so they stay concrete — that is an arbitrary choice, not a default.
import { RpcTarget } from 'capnweb';
import * as z from 'zod';
import {
ServicePlaneService,
abilityMethod,
defineAbility,
defineCapabilities,
jwksFromServiceBinding,
} from 'service-plane/service';
type Env = {
ASANA_CONNECTIONS: DurableObjectNamespace;
CONTROL_PLANE: Fetcher;
};
const capabilities = defineCapabilities({
serviceId: 'asana',
scopes: [{ id: 'asana.tasks.write', title: 'Create Asana tasks' }],
});
const asanaTasks = defineAbility({
id: 'asana.tasks',
title: 'Asana Tasks',
exposure: 'published',
access: 'plane',
scopes: ['asana.tasks.write'],
methods: {
createTask: abilityMethod({
input: z.object({
connectionId: z.string(),
name: z.string().min(1),
projectId: z.string(),
}),
output: z.object({
id: z.string(),
url: z.string().url(),
}),
scopes: ['asana.tasks.write'],
rest: { method: 'post', path: '/asana/tasks', summary: 'Create an Asana task' },
mcp: { name: 'asana_create_task', description: 'Create a task in Asana' },
}),
},
handler: ({ context, identity }) => new AsanaTasksHandler(context.env, identity),
});
class AsanaTasksHandler extends RpcTarget {
constructor(
private readonly env: Env,
private readonly identity: { serviceId: string },
) {
super();
}
async createTask(input: { connectionId: string; name: string; projectId: string }) {
const id = this.env.ASANA_CONNECTIONS.idFromName(`${this.identity.serviceId}:${input.connectionId}`);
const connection = this.env.ASANA_CONNECTIONS.get(id);
return connection.createTask(input);
}
}
export default new ServicePlaneService<{ Bindings: Env }>({
id: 'asana',
title: 'Asana Service',
version: '0.2.0',
auth: {
issuer: 'control-plane',
jwks: (c) => jwksFromServiceBinding(c.env.CONTROL_PLANE),
},
capabilities,
abilities: [asanaTasks],
});
This service mounts:
GET /.well-known/service-plane/service.json
ALL /rpc/asana.tasks
import {
ServicePlaneControlPlane,
cloudflareServiceBinding,
hmacServiceClientAuth,
} from 'service-plane/control-plane';
export default new ServicePlaneControlPlane({
signingKeys: (env) => [{ kid: '2026-07', secret: env.STS_SIGNING_SECRET }],
authenticateCaller: (c) =>
hmacServiceClientAuth({
clients: [{ clientId: 'workflow-runner', secret: c.env.WORKFLOW_RUNNER_SECRET }],
})(c),
services: (c) => [
cloudflareServiceBinding({
id: 'asana',
binding: c.env.ASANA,
grants: [{ caller: 'workflow-runner', scopes: ['asana.tasks.write'] }],
}),
],
});
The control plane mounts:
POST /.well-known/service-plane/capability-token
GET /.well-known/service-plane/jwks.json
GET /openapi.json
POST /rpc/mcp (MCP streamable HTTP)
The plane serves the OpenAPI document; to render it, mount a Hono UI extension (e.g. @hono/swagger-ui or @scalar/hono-api-reference) on plane.app pointed at /openapi.json.
For this compact local-development walkthrough, the service above leaves ingress disabled so the caller below can connect directly. Do not use this direct topology as the production boundary. Production services should enable ingress: {} and route ability calls through the control-plane broker; direct non-brokered tokens are then rejected with 403 before handler creation. See Service-Plane Ingress.
import {
abilitySession,
cloudflareServiceBindingRpc,
controlPlaneHmacTokenRequester,
type AbilityRpc,
} from 'service-plane/service';
declare const env: {
ASANA: Fetcher;
CONTROL_PLANE: Fetcher;
WORKFLOW_RUNNER_SECRET: string;
};
const asana = await abilitySession<AbilityRpc<typeof asanaTasks>>({
abilityId: 'asana.tasks',
callerServiceId: 'workflow-runner',
targetServiceId: 'asana',
scopes: ['asana.tasks.write'],
requestToken: controlPlaneHmacTokenRequester({
clientId: 'workflow-runner',
clientSecret: env.WORKFLOW_RUNNER_SECRET,
controlPlaneUrl: 'https://control-plane.internal',
fetch: env.CONTROL_PLANE,
}),
transport: cloudflareServiceBindingRpc(env.ASANA),
});
await asana.createTask({
connectionId: 'conn_123',
name: 'Follow up',
projectId: 'proj_456',
});
The repo ships an APM package with a
service-plane skill that teaches coding agents the ability model, the
security boundaries, and where to find deeper reference material. It is
distributed through this Git repo by the APM CLI, independently of npm.
Install the APM CLI once (instructions), then install the skill into a consumer project:
apm install JUVOJustin/service-plane
Or pin it as a dependency so every teammate gets the same version. Minimal
apm.yml in the consumer repo:
name: my-project
version: 1.0.0
dependencies:
apm:
- JUVOJustin/service-plane
apm install
Either way the skill deploys to your agent's native location
(.claude/skills/ for Claude Code, .agents/skills/ for Copilot, Cursor,
and others; commit apm.lock.yaml to keep installs reproducible). From
there the agent activates it automatically whenever a task touches
service-plane code — no prompting needed. The skill source lives in
.apm/skills/service-plane/; its
references are synced copies of docs/.
FAQs
Ability-first Service Plane primitives for schema-backed Cap'n Web RPC, STS capability tokens, OpenAPI, and MCP projections.
The npm package service-plane receives a total of 14 weekly downloads. As such, service-plane popularity was classified as not popular.
We found that service-plane demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.

Security News
GPT-6 Astra hits 100% on ExploitBench and finds zero-days autonomously, while independent tests reveal scope violations and monitoring gaps.

Product
Socket can now send alerts and supply chain attack notifications to Microsoft Teams, with filters that route the right updates to each channel.

Security News
pnpm 12 rewrites the package manager in Rust, cutting install times by up to 90% while preserving pnpm 11 workflows and lockfiles.