
Research
Shai-Hulud Descends to Hades: Miasma Worm Campaign Spreads with New PyPI Wave
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.
@agentick/express
Advanced tools
Express middleware for Agentick Gateway.
This is a thin adapter (~50 lines) that delegates all business logic to @agentick/gateway. Use this when you want to integrate Agentick into an existing Express application.
npm install @agentick/express
# or
pnpm add @agentick/express
import express from "express";
import { createAgentickMiddleware } from "@agentick/express";
import { createApp, Model, System, Timeline } from "@agentick/core";
const app = express();
app.use(express.json());
// Define your agent
const AssistantAgent = () => (
<>
<Model model={gpt4} />
<System>You are a helpful assistant.</System>
<Timeline />
</>
);
const agentickApp = createApp(<AssistantAgent />);
// Create middleware
const agentick = createAgentickMiddleware({
apps: { assistant: agentickApp },
defaultApp: "assistant",
});
// Mount at /api
app.use("/api", agentick);
// Start server
const server = app.listen(3000);
// Graceful shutdown - access gateway via .gateway property
process.on("SIGTERM", async () => {
await agentick.gateway.close();
server.close();
});
Creates an Express Router that delegates to an embedded Gateway.
Returns a AgentickRouter - an Express Router with an attached .gateway property for lifecycle management.
import { createAgentickMiddleware, method } from "@agentick/express";
import { z } from "zod";
const middleware = createAgentickMiddleware({
// Required: Register your apps
apps: {
assistant: agentickApp,
researcher: researchApp,
},
defaultApp: "assistant",
// Optional: Authentication
auth: {
type: "custom",
validate: async (token) => {
const user = await verifyToken(token);
return user ? { valid: true, user } : { valid: false };
},
},
// Optional: Custom methods
methods: {
tasks: {
list: method({
schema: z.object({ sessionId: z.string() }),
handler: async (params) => todoService.list(params.sessionId),
}),
create: method({
schema: z.object({
sessionId: z.string(),
title: z.string().min(1),
}),
handler: async (params) => todoService.create(params),
}),
},
health: async () => ({
status: "ok",
timestamp: new Date().toISOString(),
}),
},
});
The middleware returns a AgentickRouter which extends Express Router with:
interface AgentickRouter extends Router {
/** The underlying Gateway instance for lifecycle management */
gateway: Gateway;
}
Use .gateway for:
await middleware.gateway.close()middleware.gateway.on('session:created', ...)interface AgentickMiddlewareOptions {
/**
* Extract token from Express request.
* By default, extracts from Authorization header.
*/
getToken?: (req: Request) => string | undefined;
}
The middleware exposes these HTTP endpoints:
| Method | Path | Description |
|---|---|---|
| GET | /events | SSE stream for session events |
| POST | /send | Send message to session |
| POST | /invoke | Invoke custom method |
// Client connects to events stream
const events = new EventSource("/api/events?sessionId=main&token=xxx");
events.addEventListener("content_delta", (e) => {
const data = JSON.parse(e.data);
console.log("Content:", data.delta);
});
events.addEventListener("tool_use", (e) => {
const data = JSON.parse(e.data);
console.log("Tool call:", data.name);
});
events.addEventListener("message_end", () => {
console.log("Response complete");
});
const response = await fetch("/api/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
sessionId: "main",
message: "Hello!",
}),
});
const response = await fetch("/api/invoke", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
body: JSON.stringify({
method: "tasks:list",
params: { sessionId: "main" },
}),
});
Define methods using the method() helper for schema validation and guards:
import { method } from "@agentick/express";
import { z } from "zod";
import { Context } from "@agentick/kernel";
const middleware = createAgentickMiddleware({
apps: { assistant: agentickApp },
defaultApp: "assistant",
methods: {
// Simple method - no schema
ping: async () => ({ pong: true }),
// With Zod schema - params are typed!
tasks: {
create: method({
schema: z.object({
title: z.string().min(1),
priority: z.enum(["low", "medium", "high"]).optional(),
}),
handler: async (params) => {
// Access Agentick context
const ctx = Context.get();
return todoService.create({
title: params.title,
priority: params.priority,
userId: ctx.user?.id,
});
},
}),
// With role guards
admin: {
delete: method({
roles: ["admin"],
schema: z.object({ id: z.number() }),
handler: async (params) => todoService.delete(params.id),
}),
},
},
},
});
// Token auth
auth: {
type: "token",
token: process.env.API_TOKEN,
}
// JWT auth
auth: {
type: "jwt",
secret: process.env.JWT_SECRET,
}
// Custom auth with user hydration
auth: {
type: "custom",
validate: async (token) => {
const decoded = await verifyJWT(token);
return { valid: true, user: { id: decoded.sub } };
},
hydrateUser: async (authResult) => {
const dbUser = await db.users.findById(authResult.user.id);
return {
id: dbUser.id,
tenantId: dbUser.tenantId,
roles: dbUser.roles,
};
},
}
The middleware exposes the underlying Gateway for lifecycle management:
const agentick = createAgentickMiddleware({ ... });
app.use("/api", agentick);
const server = app.listen(3000);
const shutdown = async (signal: string) => {
console.log(`${signal} received, shutting down...`);
// Close gateway first (cleanly disconnects all sessions)
await agentick.gateway.close();
// Then close HTTP server
server.close(() => {
console.log("Server closed");
process.exit(0);
});
};
process.once("SIGTERM", () => shutdown("SIGTERM"));
process.once("SIGINT", () => shutdown("SIGINT"));
For convenience, the package re-exports common types from @agentick/gateway:
export {
Gateway,
method,
type GatewayConfig,
type MethodDefinition,
type AuthConfig,
} from "@agentick/gateway";
@agentick/gateway - Core gateway (used internally)@agentick/core - JSX runtime for agents@agentick/client - Browser/Node client SDK@agentick/server - SSE utilitiesMIT
FAQs
Express middleware and router for Agentick applications
We found that @agentick/express demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Research
Socket found 37 malicious PyPI wheels that abuse Python startup hooks to launch a Bun-powered credential stealer tied to Mini Shai-Hulud/Miasma.

Security News
RubyGems and Bundler 4.0.13 introduced an opt-in cooldown feature that delays newly published gems during dependency resolution.

Security News
pnpm 11.5 now recognizes npm staged publish approvals in release metadata, preventing those releases from being mistaken for lower-trust package publishes.