DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

@dsh-agentic-roleplay/state

State

DSH plugin for roleplay session state: one SQLite database per session, exposed to other plugins as a service over canonical models.

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add @dsh-agentic-roleplay/state@0.10.1
READMECompatibilityVersions

Compatibility and provenance

State is published as @dsh-agentic-roleplay/state and currently resolves to version 0.10.1. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
any
Release source
npm
Registry updated
11/4/2026

Versions

0.10.1stable
11/3/2026
0.10.0stable
11/2/2026
0.9.1stable
10/31/2026
Show 22 more versionsCollapse versions
0.9.0stable
10/31/2026
0.8.2stable
10/30/2026
0.8.1stable
10/30/2026
0.7.3stable
10/29/2026
0.7.2stable
10/28/2026
0.7.1stable
10/26/2026
0.7.0stable
10/26/2026
0.6.1stable
10/24/2026
0.6.0stable
10/24/2026
0.5.0stable
10/23/2026
0.4.1stable
10/22/2026
0.4.0stable
10/21/2026
0.3.6stable
10/20/2026
0.3.5stable
10/20/2026
0.3.4stable
10/19/2026
0.3.3stable
10/18/2026
0.3.2stable
10/17/2026
0.3.1stable
10/17/2026

Related plugins

Loading related plugins…

Latest
0.10.1
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
1.7 MB
Files
7
Surface
any
License
GPL-3.0-only
Source
npm
GitHub
★ 0
Weekly downloads
2,017
Security scan
✓ v0.10.1 scan passed
Last push
11/3/2026
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
0.3.0stable
10/15/2026
0.2.1stable
10/15/2026
0.1.1stable
10/13/2026
0.1.0stable
10/12/2026

Related plugins

More verified plugins in memory-context.

Hindsight Coding Agents@vectorize-io/hindsight-coding-agentsReflect-only Hindsight long-term memory for coding agents (harness-pluggable: opencode, …), with automatic background ingestion (no setup CLI).Contextdsh-contextA DeepSeek Harness plugin for context insight and management, with context dashboard and context command, for understanding how the context is made of, and how it evolves.Mnemondsh-mnemonComposable, view-based context for DeepSeek Harness. Pluggable sources and strategies, with layered memory and self-evolving skills out of the box.Archive Manager@michengai/dsh-archive-manager归档、恢复、收藏和永久删除会话,并诊断损坏的会话日志。 · Archive, restore, favorite, and permanently delete sessions, and diagnose damaged session logs.

README

@dsh-agentic-roleplay/state

The persistent session-state and memory service for DSH Agentic Roleplay, maintained by Firefox2100.

Most users should install @dsh-agentic-roleplay/all. Install this package separately when another DSH plugin needs the roleplay database, repositories, recall engine, or model-facing record tools without the complete roleplay interface.

A DeepSeek Harness plugin that keeps the state of roleplay sessions: one SQLite database per session, reached through repositories over canonical models. It does no orchestration and has no UI, so it can be installed on its own to get a roleplay database and state management without the rest of the roleplay bundle. Other plugins use it through the roleplayState service. Model-facing tools are included and can be enabled through its configuration.

Requires DSH 0.2 and Node 22.19 or later (it uses the built-in node:sqlite).

dsh plugin --profile <name> add @dsh-agentic-roleplay/state

Using it from another plugin

import type {} from '@dsh-agentic-roleplay/state'            // types `ctx.roleplayState`
import type { Context } from '@deepseek-ai/cordis'

export const inject = ['roleplayState']

export function apply(ctx: Context) {
  // Creates sessions/<uuid>/session.sqlite and opens it.
  const session = ctx.roleplayState.createSession('/path/to/sessions', {
    name: 'First night',
    world: { id: 'blackwater-observatory', name: 'The Blackwater Observatory' },
  })

  session.transaction(() => {
    const mayor = session.characters.add({ name: 'Eleanor Graves', /* … */ control: 'agent' })
    session.characterStates.create(mayor.id, { publicState: '…', innerState: '…', activity: '…' })
    session.intents.add(mayor.id, { type: 'agenda', name: '…', /* … */ })
  })

  session.characters.findByName('the mayor')       // by name or alias, ignoring case
  session.characterStates.update(1, { activity: 'looking for the key' }, { expectedVersion: 3 })
}

The service creates and opens sessions under a sessions folder you give it, shares one connection per session, and closes them all when the plugin unloads:

MethodDoes
createSession(sessionsDir, init)Creates the session folder and database and returns its repositories. The id is generated (UUID v4) unless given. Nothing is left behind if it fails.
openSession(sessionsDir, id)Returns the repositories of an existing session.
listSessions(sessionsDir)The metadata of every session under the folder (name, world, creation time, last played time, turns). A session that cannot be read is reported in problems, not thrown.
closeSession(sessionsDir, id)Releases the connection; opening again reconnects.
deleteSession(sessionsDir, id)Closes the session and removes its folder.

Session ids become folder names, so only a UUID v4 is accepted. The package also exports the same operations as plain functions (createSession, openSession, createSessionStore, …) for code that does not run inside DSH, such as tests.

The records API and the model-facing tools

The package owns how a story is remembered, not only where it is stored:

  • session.edit(edit) changes the story's records (character states, events with who took each in, beliefs, threads) together or not at all. It checks the whole edit first and throws InvalidEditError naming every problem, so a model's mistakes can be reported back to it. parseRecordsEdit(json) reads the wire format models write (snake_case) and recordsEditSchema({ characters, changes }) is its JSON schema, for a model's structured output or a tool's parameters.
  • session.records(scope) reads the records back in the same wire format.
  • session.recall({ characterId, situation, turn, policy }) is what a character is reminded of: events it took in and things it believes, by who the situation mentions, shared words and tags, importance and story-time recency; with policy.flaky the older and less important are told as faded or vague, or are gone. Age is elapsed story time from session.clock, never turn count; an unimportant event has a six-story-day half-life. It counts what it brings back as recalled, which makes it last longer.
  • session.recallStored(query, { queryVector? }) adds the session's search index to the cues: texts that match the situation by words and, with the vector of the situation, by meaning. session.searchEvents({ text, vector?, fromTurn, toTurn, minImportance, limit }) finds what happened by the same two searches, merged by reciprocal rank.
  • session.recallRanked(query, signal, { queryVector? }) is the call for anything that reminds a character of something: recall, ranked by meaning when a plugin has registered a ranker with roleplayState.rankMemories(ranker) (an embedding model, a reranker; see docs/capabilities.md). session.recallCandidates(query) gives what could be recalled, with the text to match, for a ranker. With explain: true in the query each recalled thing carries why: the cues of the moment (people named, words shared, place), what each search scored it, how much it matters, how long ago it was, how much of it is left in mind and what it was ranked by.
  • session.knowledge is the closed-world awareness graph for locations, items and directed exits (learn, knows, get, list, forget). Directional relationships are the corresponding character-to-character edges. Awareness grants identity only, not current state or whereabouts. session.planKnownMove plans through only a character's known places and exits; planMove remains the authoritative world planner.
  • session.factions, , , and store persistent organisations separately from characters that act in scenes. Membership is many-to-many; relationships involving factions are directional and double as closed-world awareness edges.

Tools registered with the DSH tool registry (defineTool, typed output, honoring the call's signal), resolved through that binding: list_characters, get_character, search_events, recall_memories, list_threads, and, only when the plugin is configured with writeTools: true, update_character_state, record_event, remember, open_thread, resolve_thread. They fail with a plain message for an agent that works in no roleplay session. Characters and other one-shot sub-agents see none of them (they are started with no tools).

Configuration

FieldDefaultMeaning
journalModedeletedelete keeps each session in a single file that can be copied; wal allows readers during writes.
writeToolsfalseAlso register the model-facing tools that change the records. Leave off where another agent is responsible for them.

Layers

LayerWhat it is
Canonical modelThe types in dsh-roleplay-model (re-exported here): Character, CharacterState, CharacterIntent, SessionMetadata, …
RepositoriesMetadataRepository, CharacterRepository, CharacterStateRepository, IntentRepository: the only access to the data. They take and return canonical models and throw the errors below.
SQLite implementationMaps rows to models and back; the only place that knows tables and SQL.
DriverSqlDriver / SqlDatabase: the few operations the implementation needs (exec, run, get, all, transaction). nodeSqliteDriver is built on node:sqlite.

Everything is synchronous, as the embedded SQLite libraries are.

This is an independent community project, not an official DSH package. Documentation · Source · Issues · GPL-3.0-only

The session

A session is the folder sessions/<uuid>/ with its database session.sqlite. The database is the only file the state needs; with the default journal mode it stays a single file that can be copied or archived.

The world itself is not stored. metadata keeps a world reference: the world's stable id (the id in its world.json, not a database id), its name, and optionally a version, a fingerprint of the content the session was started from, its source, and free-form extra fields. It is saved as one document, so provenance can grow without a schema change.

The metadata also carries what a list of sessions shows: the session's name (chosen when it is created), its creation time, the time of the last play (absent until a turn has been played) and the number of turns played. Whatever plays a turn calls metadata.recordTurn(), which counts it and sets the time.

Characters have session-local integer ids. source_id keeps the id the character had in the world, so a session can be traced back to its world; characters created during play have none.

Schema (version 1)

TableHolds
metadataKey/value rows: session.id, session.name, session.created_at, session.last_played_at, session.turns, world (JSON), plus free-form namespaced entries.
charactersThe definition: name, age, gender, pronouns, kind, tier, role, summary, personality, background, appearance, speech, and control (player or agent, chosen for the session). source_id is unique.
character_aliasesOne row per alias, in order, with a case-folded key for lookup.
character_stateThe state that changes in play: public state, inner state, activity, version, updated_at. One row per character.
character_emotionOptional baseline and immediate valence/arousal/dominance of a state.
intentsA character's intents: type, name, description, status, horizon, priority, urgency, plan, open threads, constraints, deadline.
relationships, consolidation_itemsHow a character stands towards another (a profile per direction: label, summary, familiarity, trust, affinity, tension) and the characters and places made up in play that still have to be fitted into the world. lintWorld reports what is inconsistent. The edit can make characters, places and ways when it is the authoring variant (recordsEditSchema({ authoring: true })).
entity_knowledgeExplicit character-to-location/item/exit awareness: the first learned turn and optional last directly observed turn. Absence means unknown; current facts remain in state, perception and memory.
factions, faction_aliases, faction_state, faction_memberships, faction_relationships, faction_intentsOrganisations, their institutional state and strategy, many-to-many membership, and directional relationships involving a faction.
slots, items, item_holdings, openers, event_itemsThings (one kind for items, equipment and containers: quantity, condition, notable, hidden, the slot it is worn in, a container state, an owner), where each is (a place, a character's hands or a slot, or inside a container item), the places on the body something can be worn (with defaults, data per session), what opens each lock (on items and exits), and which events are about which items. does what a character does with a thing (take, drop, give, put, wear, remove, open, close, lock, unlock, reveal) by the rules of the story and says every reason when it cannot.

Events are the ground truth; perceptions (which stay revisable: updatePerception, addPerception), memories and summaries are derived from them and can be rebuilt. The repositories are events, memories, threads, summaries and pendingCommits next to the ones for characters.

Deleting a character deletes everything that belongs to it. The tables are STRICT, enumerations and ranges are CHECK constraints, and foreign keys are enforced. The file records its schema version in user_version and carries an application id, so a file that is not a session database is refused.

Changing the schema

Migrations are applied in order when a session is opened and are never edited once released: a change is a new entry in src/sqlite/schema.ts, and a test pins the migrations of each release. A database from a newer version is refused rather than damaged.

Before a file that is behind the latest schema is upgraded, it must pass SQLite's quick integrity check (a damaged file is refused with CorruptDataError, untouched) and a copy of it as it was is written to migration-backups/schema-<version>.sqlite beside the database, once per old version. migrationBackupPath(location, version) says where.

Errors

ErrorWhen
NotFoundErrorA row, character or session file does not exist.
ConflictErrorA repeated source_id, a state created twice, a stale expectedVersion, or creating a session where one exists.
InvalidValueErrorA value is outside what the schema allows.
SchemaErrorThe file is not a session database, or comes from a newer version.
CorruptDataErrorStored data cannot be read back as a model.
factionStates
factionMemberships
factionRelationships
factionIntents
  • roleplayState.bind(resolver) tells the tools which roleplay session an agent works in (the plugin that runs the agents supplies it, with the turn being played and the memory policy).
  • changeItem
    clock, time_logThe story's own time: one row with the mode (simulated or real) and the instant, and every step it took (start, elapsed, real, skip, resync) with the turn and round. session.clock starts it, moves it forward, sets it in either direction when the mode changes, and tells when a round began.
    routine_windows, engagements, engagement_participantsThe recurring day of each character (windows of the day with what it is doing and where, first fit applies) and dated commitments with who made them and whether they were kept. session.routines and session.engagements; agendaAt merges them with the character's goals (intents).
    locations, exits, placementsPlaces (with features), the ways between them (one direction each, open / locked / blocked, optional travel seconds) and where things stand (a character: place, position, feature; the same table will place items). session.planMove / session.move move a character over open exits only (InvalidMoveError names every reason); the edit wire format can make places, change exits and move characters.
    eventsWhat objectively happened: turn, round, text, importance (1 to 5), tags. event_involves lists the characters an event is about. Events are immutable: a draft until sealed, final afterwards (events.seal()); updating or removing a sealed one throws ConflictError.
    perceptionsWhat one character took in of an event, in its own terms: mode (witnessed, heard, told, inferred), content, a gist for when it fades, an accuracy label (never shown to the character), and how often it was recalled. One per character and event.
    memories, memory_evidenceWhat a character believes or knows beyond single events: kind, text, subjects, importance, confidence, formation turn, and the perceptions that support or contradict it.
    story_threadsThings not settled yet: promises, mysteries, goals; open or resolved.
    summariesThe account of the story for the conversation's head: digests of recent turns and chapters of older ones, each with the turns it covers.
    recall_items, recall_fts, recall_vocab, recall_vecThe search index: one row per perception, memory and event, indexed by words (FTS5) and, once vectors are stored, by meaning (sqlite-vec, cosine, partitioned by character). store.recallIndex lists the texts without a vector (pending), stores vectors (store, which fixes the model and dimensions of the session's vectors) and searches (lexical, vector). Vector support is optional: without the extension everything but vector works.
    pending_commitsRecorded rounds whose events and memories are not written yet, kept so that a failure loses nothing.