Guide: Code projects
A code project (Next.js, Vite, TanStack Start or Expo web), not on a design. Use it when the user asks about the screens of an app in a folder, for example "sho
A code project (Next.js, Vite, TanStack Start or Expo web), not on a design. Use it when the user asks about the screens of an app in a folder, for example "show me all screens".
Start
Pass the project folder as project. No app, no browser and no open tab is necessary. Knighn starts the dev server and waits until it is ready.
execute({ project: '/Users/me/code/shop', input: 'return await Screens()' })
projectis"."(the folder the local server runs in), an absolute path, or the id of an open project tab.- On the hosted server, the folder must be in a folder that the Mac shares (Settings > Remote), and the Mac must be online.
GetAppState()withprojectalways answers. With noproject, it lists the projects inprojects, each with anidthatprojectaccepts, and what a code project supports.search("", { kinds: ['project'] })finds the same projects.- To show the project on the canvas of the app, call
OpenProject(path)or give the linkLinkTo('code/open').
With project, execute has the project helpers below and not the design API. Read and edit the project files with your own tools.
Screens
await Screens({ routes, states, widths, out, restart, hideOverlays }) draws each route and gives one item for each picture:
const screens = await Screens()
// [{ route: '/venue/[id]', file: 'src/app/venue/[id].tsx', state: 'Default',
// source: 'story', params: { id: 'nd7b…' }, width: 390,
// image: '/Users/me/Library/Caches/Knighn/screens/shop-1a2b/venue_[id].Default@390.png' }]
imageis the path of a PNG file on the Mac. There is no limit on the number of pictures: 24 screens come back in one call. Read a picture with your own tools.routeslimits the routes.widthsgives the widths (by default the viewports the project chose in Knighn, else 390 for an Expo app and 1440 for a web app).outgives the folder for the pictures.- The pictures do not show the app's start-up overlays: its onboarding or first-run dialog, cookie and consent banners, chat widgets and pop-ups.
hideOverlays: falsekeeps them. - Each Storybook story of a route's component is a state of the route.
states: 'all'draws each state of each route.states: ['Empty', 'Loading']draws those states. - Knighn fills dynamic segments (
/venue/[id]) from sample data. It reads the sources in this order: theparamsof the route in therouteslist ofknighn/scenes.knighn.tsx({ route: '/venue/[id]', params: { id: 'demo' } }), then the Storybook stories of the route's component (parameters.paramsgives the route parameters), then a guess from the route's types.sourcesays which one it used. - An Expo app that has a Storybook route shows each story on that route, with the story's own sample data. Native views (
@expo/ui) are drawn as web stand-ins.
Watch and Changes
const { cursor } = await Watch()
// ...edit a file with your own tools...
const changes = await Changes(cursor, { wait: 10000 })
// { cursor, files: ['src/app/venue/[id].tsx'], screens: [/* only the screens that changed */] }
Changes(cursor) gives only the screens that the changed files reach, with new pictures, and the next cursor. Do not poll: wait holds the call until a file changes or the time ends.
Selection and proposals
await GetSelection()gives the elements the person selected on the canvas, each with its sourcefile:line:column. With no open tab, nothing is selected.await Screenshot('/pricing', { width: 1440 })gives one picture in the result.Propose(...)shows changes for the person to see before and after, and writes nothing. Knighn draws each screen twice, Now and Proposed, with the change in a real render, and lists each proposal in the Proposals panel for the person to accept or reject whole. The project host keeps them: a tab that opens later shows them.- Always give a
note(or atitlefor a group): one plain sentence that says what changes for the person. Do not put class names in it; the code shows only when the person asks.
// A class or text change on one element: one proposal each.
await Propose([
{
at: 'src/app/page.tsx:12:7',
add: ['p-6'],
remove: ['p-4'],
note: 'More room around the heading'
},
{ at: 'src/app/page.tsx:14:9', text: 'Start free', note: 'A clearer button label' }
])
// Any other file change: a patch (find must occur once), or the whole file with the hash you read.
await Propose({
file: 'src/components/Card.tsx',
find: '<Button',
replace: '<IconButton',
note: 'Use the icon button'
})
// One change across several elements or files: a group, accepted or rejected as one item.
await Propose({
title: 'One panel width',
note: 'All four panels are 320 px wide',
edits: [{ at: 'src/panels/Left.tsx:8:5', add: ['w-80'], remove: ['w-72'] }],
patches: [{ file: 'src/panels/Right.tsx', find: 'w-96', replace: 'w-80' }],
route: '/settings'
})
- A patch renders in a temporary copy of the project with its own dev server, so the Proposed frame shows the real result.
routenames the screen to show a patch on, andatthe element its pin goes on, when the edits do not tell.
Failures
Each failure is JSON with the cause and the exact next call:
{ "error": "dev server failed: …", "log": "…", "retry": "Screens({ restart: true })" }
Do the call in retry. Read log first when it is there.
With only a shell
knighn screens [folder] --out dir does the same as Screens() with no MCP. --json prints the result as JSON. Options: --routes, --states, --widths, --restart, --keep-overlays.