Skip to main content

Files, Store, and State

$.fs reads and writes files as the Claude Code process. $.store keeps values of the plugin between sessions. $.state holds named values with versions during a session. A render hook that reads a state value is drawn again when the value changes.

There is no switch. A file is at most 4 MiB, and $.store holds at most 4 MiB of JSON. $.fs uses the real file system. $.store and $.state belong to the plugin.

Official pages: Draw in the Interface, Mods Reference. Source: the program (types-2.1.304.d.ts). In a "Where it can be used" cell, "Run time" means in a hook, in a closure that a hook drew, or in a timer callback. It does not mean inside register.

Example​

on('turn.complete', async ($, e, next) => {
const count = Number((await $.store.get('count')) ?? 0) + 1
await $.store.set('count', count)
return next(e)
})

Members​

ItemStatusWhat it doesHow it worksWhere it can be used
$.fs.readDocumentedReads a file and returns its text. With { as: "bytes" } it returns the bytes as { base64 }.Three call forms. Rejects when the file is missing or over 4 MiB. options.as is "text" (default) or "bytes".Run time.
$.fs.writeDocumentedWrites text to a file, creating it and its directories as needed.(path, text) => Promise<void>. path is relative to the working directory, or absolute. text is the whole new content.Run time.
$.fs.listDocumentedLists a directory: { name, kind, size, mtimeMs, isLink } for each entry.(path?) => Promise<FsEntry[]>. A symbolic link is other with isLink.Run time.
$.fs.existsDocumentedReturns whether the path exists.(path) => Promise<boolean>. Rejects only for a network location.Run time.
$.fs.statDocumentedReturns { kind, size, mtimeMs, isLink } of the path. Rejects when missing.(path, options?) => Promise<FsStat>. With { resolve: true } it also gives realPath. A missing path rejects with ENOENT.Run time.
$.fs.ancestorsDocumentedReads the named instruction files in every directory above the session's first working directory, the way the engine reads CLAUDE.md.(request) => Promise<readonly FsAncestor[]>. Returns the .md files on the path from the root to a file, root first.Run time.
$.store.getDocumentedReturns the value under key, or undefined when unset.(key) => Promise<unknown>.Run time.
$.store.setDocumentedSets key to value, which must be JSON data.(key, value) => Promise<void>. Rejects a function, a cycle, or a store over 4 MiB.Run time.
$.store.deleteDocumentedRemoves key.(key) => Promise<void>.Run time.
$.store.keysDocumentedReturns every key set, in insertion order.() => Promise<string[]>.Run time.
$.state.getDocumentedResolves the value under ref and its version. A value never written is undefined at version 0.(ref) => Promise<StateRead>. plugin and key must be literals in the source. Resolves { value, version }.Run time.
$.state.setDocumentedWrites value under ref, which must be this plugin's own. Sites that read it while drawing are drawn again, at the redraw rate.(ref, value, options?) => Promise<StateSetResult>. ifVersion writes only at that version. Resolves { isSet, version }.Not while a ui.render hook draws.

State Helpers Imported from claude-code​

These helpers are pure code. They run in the plugin's own environment.

ItemStatusWhat it doesHow it works
atomDocumentedA named value with an initial value. read gives the initial value while nothing is written, so never undefined.Type AtomFunction.
deriveDocumentedA value computed from atoms and references, cached by their versions.Type DeriveFunction. Example: derive([workers], list => list.filter(w => w.isBusy).length).
memberOfDocumentedA family's member for the instance being drawn, keyed by e.requestId.Type MemberOfFunction. Example: await read($, memberOf(isOpen, e)).
readDocumentedReads an atom, a derived value, or a reference through $.state.get while a ui.render hook draws. That subscribes the drawing.Type ReadFunction. Example: await read($, count).
updateDocumentedReads, applies fn, writes with ifVersion, and tries again on a miss. A handler closure calls it.Type UpdateFunction. Example: <Button key="more" onPress={() => update($, count, n => n + 1)} />.

Events Raised by These Calls​

For each call, a hook above the caller returns next(e), { deny: reason }, or { value }.

ItemStatusThe argumentInput and value
fs.readDocumented$.fs.read(path, { as }). as is text unless the caller asked for bytes.Input { path: string, as: FsReadAs }. Value string | FsBytes.
fs.writeDocumented$.fs.write(path, text)Input { path: string, text: string }. Value void.
fs.listDocumented$.fs.list(path)Input { path: string }. Value FsEntry[].
fs.existsDocumented$.fs.exists(path)Input { path: string }. Value boolean.
fs.statDocumented$.fs.stat(path, { resolve }). resolve is false unless asked.Input { path: string, resolve: boolean }. Value FsStat.
fs.ancestorsDocumented$.fs.ancestors({ names, of, below })Input FsAncestorsRequest. Value readonly FsAncestor[].
store.getDocumented$.store.get(key)Input { key: string }. Value unknown.
store.setDocumented$.store.set(key, value)Input { key: string, value: unknown }. Value void.
store.deleteDocumented$.store.delete(key)Input { key: string }. Value void.
store.keysDocumented$.store.keys()Input NoArgs. Value string[].
state.getDocumented$.state.get(ref): the reference itself (plugin, key, and a family member's id). Pinned.Input StateGetEvent. Value StateRead.
state.setDocumented$.state.set(ref, value, { ifVersion }) plus previous, what stood there.Input StateSetEvent. Value StateSetResult. Only the value's owner raises it.