npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shardworks/parlour-apparatus

v0.1.123

Published

The Parlour — multi-turn conversation management apparatus

Downloads

1,961

Readme

@shardworks/parlour-apparatus

The Parlour manages multi-turn conversations within the guild. It provides the structure for two kinds of interaction: consult (a human talks to an anima) and convene (multiple animas hold a structured dialogue). The Parlour orchestrates turns — deciding when and for whom to call The Animator — while delegating session launch to The Animator and context composition to The Loom.

The Parlour sits downstream of both The Animator and The Loom in the dependency graph: stacks <- animator <- parlour and loom <- parlour.


Installation

Add to your package's dependencies:

{
  "@shardworks/parlour-apparatus": "workspace:*"
}

The Parlour requires The Stacks, The Animator, and The Loom to be installed in the guild.


API

The Parlour exposes a ParlourApi via its provides interface, retrieved at runtime:

import type { ParlourApi } from '@shardworks/parlour-apparatus';

const parlour = guild().apparatus<ParlourApi>('parlour');

create(request): Promise<CreateConversationResult>

Create a new conversation. Sets up the conversation and participant records but does NOT take a first turn.

const { conversationId, participants } = await parlour.create({
  kind: 'consult',
  topic: 'Help me refactor the session layer',
  turnLimit: 10,
  cwd: '/workspace/shardworks',
  participants: [
    { kind: 'human', name: 'Sean' },
    { kind: 'anima', name: 'Artificer' },
  ],
});

| Parameter | Type | Description | |---|---|---| | kind | 'consult' \| 'convene' | Conversation kind | | topic | string | Seed topic / initial prompt (optional) | | turnLimit | number | Max anima turns before auto-conclude (optional) | | cwd | string | Working directory — persists for the conversation's lifetime | | participants | ParticipantDeclaration[] | Who is in the conversation | | eventId | string | Triggering event id (optional, for clockworks) |

takeTurn(request): Promise<TurnResult>

Take a turn in a conversation. For anima participants, weaves context and calls The Animator. For human participants, records the message as context for the next anima turn.

// Human turn — records message, no session launched
await parlour.takeTurn({
  conversationId,
  participantId: humanId,
  message: 'What about the error handling?',
});

// Anima turn — launches a session via The Animator
const result = await parlour.takeTurn({
  conversationId,
  participantId: animaId,
  message: 'What about the error handling?', // or omit to use topic
});
// result.sessionResult contains the Animator's SessionResult
// result.turnNumber is the 1-indexed turn count
// result.conversationActive indicates if the conversation is still open

takeTurnStreaming(request): { chunks, result }

Same as takeTurn(), but streams output chunks as the session produces them. Returns synchronously with { chunks, result } — same pattern as The Animator.

const { chunks, result } = parlour.takeTurnStreaming({
  conversationId,
  participantId: animaId,
});

for await (const chunk of chunks) {
  if (chunk.type === 'text') process.stdout.write(chunk.text);
  if (chunk.type === 'turn_complete') console.log(`\nTurn ${chunk.turnNumber} done`);
}

const turnResult = await result;

Chunk types include all SessionChunk types from The Animator, plus:

  • { type: 'turn_complete', turnNumber, costUsd? } — emitted after the session completes

nextParticipant(conversationId): Promise<Participant | null>

Get the next participant in line. For consult: always returns the anima. For convene: round-robin by insertion order. Returns null if the conversation is ended or the turn limit is reached.

end(conversationId, reason?): Promise<void>

End a conversation. Reason defaults to 'concluded'. Idempotent — safe to call on already-ended conversations.

list(options?): Promise<ConversationSummary[]>

List conversations with optional filters by status, kind, and limit. Returns summaries ordered by createdAt descending.

show(conversationId): Promise<ConversationDetail | null>

Show full detail for a conversation including all turns, participant list, and aggregate cost.


Configuration

No guild-level configuration is required. The Parlour reads its dependencies from the guild's apparatus registry at startup.


Support Kit

The Parlour contributes two books and three tools to the guild:

Books

| Book | Indexes | Contents | |---|---|---| | conversations | status, kind, createdAt | Conversation documents with nested participant records | | turns | conversationId, turnNumber, participantId, participantKind | Per-turn records linking conversations to Animator sessions |

Tools

| Tool | Permission | Description | |---|---|---| | conversation-list | read | List conversations with optional status/kind filters | | conversation-show | read | Show full conversation detail including all turns | | conversation-end | write | End an active conversation (concluded or abandoned) |


Key Types

interface CreateConversationRequest {
  kind: 'consult' | 'convene';
  topic?: string;
  turnLimit?: number;
  participants: ParticipantDeclaration[];
  cwd: string;
  eventId?: string;
}

interface ParticipantDeclaration {
  kind: 'anima' | 'human';
  name: string;
}

interface TurnResult {
  sessionResult: SessionResult | null;  // null for human turns
  turnNumber: number;
  conversationActive: boolean;
}

interface ConversationSummary {
  id: string;
  status: 'active' | 'concluded' | 'abandoned';
  kind: 'consult' | 'convene';
  topic: string | null;
  participants: Participant[];
  turnCount: number;
  totalCostUsd: number;
  // ... timestamps, turnLimit
}

See src/types.ts for the complete type definitions.


Exports

The package exports all public types and the createParlour() factory:

import parlourPlugin, { createParlour, type ParlourApi } from '@shardworks/parlour-apparatus';

The default export is a pre-built plugin instance, ready for guild installation.