.agents/skills/create-integration-package/SKILL.md
This skill is utilized when creating a web framework integration package. After examining the given framework, a feasibility assessment is conducted regarding the creation of an integration package. If implementation is feasible, the package is generated; if it is not possible, the rationale is provided to the user.
npx skillsauth add fedify-dev/fedify create-integration-packageInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Follow these steps in order to implement the integration package.
Research the web framework for which the integration package will be
implemented using web searching. Fedify operates as middleware via
Federation.fetch.
The critical question is whether the given framework can act as a server
framework and supports adding middleware. Search for and investigate
whether the relevant functionality is available. Assess feasibility based
on the research. If research indicates implementation is not possible,
explain the reasons in detail to the user and stop. If feasible, proceed
to create the package. Even during package creation, it may turn out to be
infeasible. In that case as well, explain the reasons in detail to the
user and stop.
Framework documentation and the actual API of the installed version can differ. For example, hook names or middleware signatures may change between major versions, or the underlying runtime may expose different APIs than what the framework docs describe. During research, always check the actual installed version in the workspace:
Prioritize usability above all else. The most important goal is that the package integrates smoothly with the framework so users do not experience friction when connecting it.
Create the package directory inside the packages/ directory. For example, if
the framework is named “framework”, create the directory packages/framework/.
Copy the template files from the package/ directory into the directory you created. Use these commands in the root path:
mkdir -p packages/framework
cp -r .agents/skills/create-integration-package/package/* packages/framework/
Then, implement the package according to the framework. Since the comments in the template are instructions for the developer to follow, please remove them once the implementation is complete.
Unless there are significant hurdles, please set up the package to publish on both JSR and NPM. This means including both deno.json and package.json files, and ensuring the code is compatible with both Deno and Node.js/Bun environments.
After writing deno.json and package.json (or whenever you add or
change dependencies), run mise run install to update both deno.lock
and pnpm-lock.yaml. This ensures all lockfiles stay in sync.
Add additional definitions as appropriate based on context. Aside from the
main integration function and the ContextDataFactory type, keep module
exports to a minimum to avoid confusing users.
When a request arrives, the integration middleware calls
federation.fetch(). If Fedify has a route for the path and the client's
Accept header includes an ActivityPub media type such as
application/activity+json, Fedify generates and returns the JSON-LD
response directly. Framework-side routing does not execute.
404 Not FoundWhen federation.fetch() does not recognize the path, it invokes the
onNotFound callback. The integration should delegate to the framework's
next handler so that non-federation routes (HTML pages, API endpoints,
etc.) are served normally.
406 Not AcceptableWhen Fedify owns the route but the client does not accept an ActivityPub
media type (e.g., a browser requesting text/html), it invokes the
onNotAcceptable callback. The correct behavior is not to return
406 immediately. Instead, give the framework a chance to serve its own
response (e.g., an HTML page at the same path). Only return 406 if the
framework also has no content for that path (i.e., the framework would
return 404). In Hono this looks like:
async onNotAcceptable(_req: Request): Promise<Response> {
await next();
if (ctx.res.status !== 404) return ctx.res;
return new Response("Not acceptable", {
status: 406,
headers: { "Content-Type": "text/plain", Vary: "Accept" },
});
},
Some frameworks define and use their own Request type internally instead
of the Web API Request. If the target framework does so, write
conversion functions within the integration package to translate between
the Web API Request and the framework's native Request.
The final failure 406 response uses this form:
new Response("Not acceptable", {
status: 406,
headers: {
"Content-Type": "text/plain",
Vary: "Accept",
},
});
A consistent naming convention for the main function has not yet been
established, but there is an open naming convention issue. If the issue
has been resolved by the time this skill is executed, update this section.
As a temporary convention, respect conventions of the framework : name it
fedifyMiddleware if the official documentation calls it as middleware, or
fedifyHandler if it's called a handler.
The package README.md must include the following:
deno.jsonA deno.json is required to publish to JSR.
package.jsonA package.json is required to publish to npm.
tsdown.config.tsA tsdown.config.ts is required for the build in Node.js and Bun environments.
Refer to the “Adding a new package” section in CONTRIBUTING.md and perform the required updates. Record the package addition in CHANGES.md.
You can test the integration using mise test:init, which will be explained
later, but write unit tests as well if possible. Name test files with the
*.test.ts convention (e.g., src/mod.test.ts).
You can import the test function from @fedify/fixture for runtime-agnostic
tests that work across Deno, Node.js, and Bun. Validate the values with
node:assert/strict assertions.
Warning:
@fedify/fixtureis a private workspace package and must never be imported from published (non-test) source files. Only import it in*.test.tsfiles.
If the framework relies on virtual modules, build-time code generation,
or other mechanisms that make @fedify/fixture impractical, you may use the
framework's own test utilities or a compatible test runner (e.g., vitest).
Document the choice in the test file so future contributors understand why a
different runner was chosen.
At a minimum, test the following scenarios (see packages/fastify/src/index.test.ts for a thorough reference):
onNotFound
fallthrough).onNotAcceptable + framework 404).onNotAcceptable + framework 200).federation.fetch() invocation with
onNotFound/onNotAcceptable (see “Request flow” for the
expected fallthrough behavior)ContextDataFactory typeRequest/Responsemise run installAdd keywords related to the framework in .hongdown.toml and cspell.json in
root path. Especially, the package name @fedify/framework should be added to
the .hongdown.toml.
After implementation, run mise run fmt && mise run check.
If there are lint or format errors, fix them and run the command again until
there are no errors.
Unless there are critical blockers (e.g., the package fails to build or tests do not pass), strongly consider proceeding immediately with the following two skills to complete the full integration:
@fedify/init package so users can select
it when creating a new project. Also, you can test the package with
fedify test:init after adding it to @fedify/init.Developing the package while implementing examples allows you to catch package errors early. However, to facilitate the review process, pull requests should be submitted separately; therefore, please ensure your commits are logically separated. commit skill can help you with this.
development
Help the user migrate Fedify code between versions. Use when the user needs to upgrade their Fedify version, fix breaking-change errors, or update deprecated API usage.
tools
Help the user set up Fedify inbox listeners for handling incoming ActivityPub activities. Use when the user needs to handle Follow, Like, Announce, Create, Undo, or other activity types delivered to their inbox.
testing
Look up a Fediverse Enhancement Proposal (FEP) and explain how to implement it with Fedify. Use when the user asks about a specific FEP by ID (e.g., FEP-8fcf, FEP-1b12) or wants to implement a fediverse standard in their Fedify application.
tools
Use this skill whenever writing JavaScript or TypeScript code that uses Fedify to build an ActivityPub server, handle federation activities, implement fediverse features, or integrate Fedify with a web framework such as Hono, Express, Next.js, Nuxt, Fastify, Koa, NestJS, Astro, SvelteKit, Fresh, h3, Elysia, or Cloudflare Workers. Covers the `Federation` builder pattern, actor/inbox/outbox/collection dispatchers, inbox listeners, vocabulary objects from `@fedify/vocab`, key pair management, HTTP Signatures, Object Integrity Proofs, the `KvStore` and `MessageQueue` interfaces, database adapter packages, structured logging with LogTape, OpenTelemetry tracing, the `fedify` CLI toolchain, and common mistakes. Also apply when the user mentions ActivityPub, federation, fediverse, WebFinger, NodeInfo, FEPs, or Mastodon interoperability, even if they do not name Fedify explicitly.