Tandem, Pro
A project tracker for Next.js where coding agents take issues beside people. Install it into a new project, then rewrite its sample API to read your own issues and connect your own agents.
Tandem is a whole app made of Dashboardblocks blocks: an Inbox, Issues as a list or a board with saved views, Triage for what comes in from Slack, Sentry and support, the running Cycle and the next one, Projects with their timeline, Insights, Agents and Settings, with a page for each issue, project and agent. A person always owns an issue, and a coding agent can take it as their delegate: it works through its steps, asks when it's stuck, and hands back a change to merge. Every page reads and writes through one sample API, so the app works as soon as it's installed. Open the preview to try it first.
Install
Tandem comes with All-Access and installs with the shadcn CLI.
-
Make a Next.js project with shadcn set up, at shadcn create (opens in a new tab) or with the CLI:
npx shadcn@latest init --template next -
Add the
@dashboardblocks-proregistry and your token, as Installation shows. -
Install Tandem:
npx shadcn@latest add @dashboardblocks-pro/tandem-next --overwrite -
Run
npm run devand open/issues.
With --overwrite, the CLI replaces any file you have that Tandem also ships, such as shadcn components and blocks you've changed and a proxy.ts, so commit first and check the diff. Without it, the CLI asks about each of those files, and skips them all when it can't ask. Your root layout, home page and theme stay as they are, and Tandem takes your shadcn style, component library and icon set.
What it adds
| Path | What's there |
|---|---|
app/(tandem)/ | The routes. Each one loads its page's data from the sample API and passes it to the page, and each section's actions.ts holds its Server Actions. |
components/tandem/pages/ | A component per page. They take data and callbacks as props and know nothing about Next.js. |
lib/tandem/api/ | The sample API: async functions in index.ts, their types in types.ts, and the sample team's issues, cycles, projects, agents and sessions in data/. |
components/tandem/next/ | The layout, the session, the actions shared by several pages, and the timer that reads a page again while an agent works. |
components/tandem/routes.ts | The list of pages that the tabs, the account menu and ⌘K search read. |
components/tandem/ | The parts every page shares: the app shell, the logo, the link adapter, the open issue, and the issue views and filters the sample API also reads. |
proxy.ts | Runs Tandem's proxy on its pages. |
In a project with a src/ folder, they go in src/. The blocks Tandem uses install next to your other blocks in components/dashboardblocks/.
Use your own data
Pages never load data themselves. Each route file calls functions from lib/tandem/api, and each change goes through a Server Action that calls one too. To show your own issues, rewrite the bodies of those functions and keep their types. The pages, routes and actions stay as they are.
- Start with the page you need first. Its route file in
app/(tandem)/names the functions it calls, such aslistIssuesandgetIssueCountsfor Issues. - Rewrite each function to query your database and return the type
types.tsgives it. A write returns a result the page shows, such as a refusal with its reason, so keep returning one. - Once nothing reads
data/any more, delete it.
Every read and write takes the session first, which names the member who is signed in. Each write checks that member's role in index.ts before it changes anything: admins manage members, agents, labels, integrations and the workspace, and only admins hand work to an agent marked for admins, take it off an issue or stop it. Reads check that the member is still in the team. Keep those checks when you move a write to your database.
Keep what people change
The sample API keeps its changes in the server's memory, in one copy every visitor shares, and starts that copy again once nobody has opened the app for ten minutes. Your database replaces it: once a write stores its change, the next read shows it, on every server.
Connect your agents
An agent session is the sample's stand-in for your agent runner. Delegating an issue (updateIssues with a delegateId) starts a session, and the sample plays its steps from data/sessions.ts against the clock, then hands back a pull request and moves the issue to In review. Pages with a session at work read themselves again every 3 seconds (LiveRefresh in their route files).
To use your own runner, start a run where updateIssues starts a session, and have listAgentSessions, getAgent and getIssue read its steps, question and pull request from where your runner reports them. answerQuestion sends a person's answer back to the run, stopSession stops it, and mergeChange and closeChange merge or close its pull request on GitHub. Connections to GitHub, Slack and Sentry are in listIntegrations and changeIntegration.
Add your auth
components/tandem/next/session.ts tells every page whether someone is signed in and who they are. For now Tom, an admin of the sample team, is signed in until he signs out. Change isSignedOut and getSession to read your auth library's session, with the member's own id.
The /sign-in and /sign-out routes in proxy.ts stand in for your auth library's own. Once you add yours, take them out of its matcher and out of components/tandem/next/proxy.ts, and point the sign-in and sign-out links at your library's pages: they're in components/tandem/next/next-shell.tsx, components/tandem/pages/settings-members-page.tsx and components/tandem/pages/settings-general-page.tsx.
If you had a proxy.ts before, put yours back and call tandemProxy(request) from components/tandem/next/proxy.ts for the paths in the matcher of the one Tandem installed.
Orion
An AI assistant for teams, for Next.js, on the AI SDK and Claude. Install it into a new project, add your Anthropic key, then rewrite its sample API to keep chats and settings in your own database.
Store
A full store dashboard built from Dashboardblocks, with header filters, stats, revenue, channels, products, a checkout funnel, month-to-date revenue and low stock.