Skip to content

Paperworlds/textworkspace

Repository files navigation

textworkspace

Meta CLI and package manager for the Paperworlds text- stack.

One install, one CLI surface. Bootstraps tools, manages workflows, and gives your repos — and the agents working on them — a shared communication layer: threads, decisions, specs, and ideas, all queryable from the terminal.

Install

pipx install textworkspace
tw init
tw shell install --fish      # or --bash / --zsh

tw init discovers existing tools, prompts for missing ones, and bootstraps Go binaries from GitHub releases. The shell wrapper is required for commands that need to modify shell state (tw switch, ta switch).

Optional — enable tab completion:

env _TW_COMPLETE=fish_source tw > ~/.config/fish/completions/tw.fish
env _TEXTFORUMS_COMPLETE=fish_source textforums > ~/.config/fish/completions/textforums.fish

What it gives you

1. One tool to manage the stack

tw init              # guided first-run, bootstraps binaries
tw status            # unified view: profile, proxy, servers, sessions
tw doctor            # health + stale paths + spec conformance across repos
tw up / tw down      # bring the whole MCP fleet up / down via textserve
tw update [tool]     # update managed binaries and packages
tw dev install       # install every tool from its local repo (editable mode)
tw sync              # reinstall after pulling; also reconciles combos
tw which <tool>      # where is this binary installed, what version

Each installed tool also becomes a passthrough: tw proxy <anything>, tw serve <anything>, tw read <anything>, tw accounts <anything>, tw map <anything> forward unknown subcommands to the real binary — so tw is one muscle-memory entry point, not a shim that hides features.

2. Workspaces + combos

A workspace is a named join of profile + servers + project — one command to switch context. Combos are YAML recipes for multi-step workflows.

tw start data              # switch profile, start servers, open a session
tw start data my-session   # same, custom session name
tw stop data
tw workspaces list / status / add / edit

tw <combo> [args]          # any combo name becomes a top-level command
tw --dry-run <combo>       # preview without executing
tw combos list / edit / export / update / remove
tw combos install gh:paperworlds/textcombos/workday

Example combo:

combos:
  workday:
    description: Start work environment
    args: [profile]
    steps:
      - run: accounts switch {profile}
      - run: proxy start
        skip_if: proxy.running
      - run: servers start --tag default

3. Repo registry + profiles

tw keeps a registry of repos you work on — personal, work, scratch — so every cross-repo command (forums, ideas, specs) agrees on what "mono" or "textread" means. Filter by profile to separate work from personal.

tw repo add mono /Users/projects/paradigm/mono --profile work
tw repo list [--profile work]
tw repo move mono /new/path   # updates config + ~/.claude/projects + every tool's own config
tw repo import                # pull repos from any tool that exposes them

When a folder moves, tw repo move orchestrates: rename on disk, rewrite config.yaml, rename ~/.claude/projects/<encoded>, and call each installed tool's <tool> repo move to update downstream state. tw doctor aggregates STALE <name> <path> warnings from every tool that implements the contract.

4. textforums — threads, pins, decisions, inbox

Async notes, bug reports, cross-repo coordination — agents and humans in the same channel. Threads live in ~/.textforums/<slug>/thread.yaml.

textforums new --title "proxy status broken" --repo textworkspace --tag bug
textforums list --repo textworkspace --status open
textforums show <slug>
textforums add <slug> --content "reproduced on 0.4.2"
textforums close <slug> --content "shipped in 0.4.3"

Also available as tw forums <sub> — same commands, same semantics.

Pins — mark a thread urgent so it surfaces above everything else:

textforums pin <slug>                      # priority=high
textforums pin <slug> --until 2026-12-31   # auto-expire
textforums new --pin --title ""           # pin on create

Decisions — promote a concluded thread to canonical, ADR-lite:

textforums decide <slug> --summary "Use protobuf for the wire format."
tw forums decisions list [--repo X] [--query T] [--since YYYY-MM-DD]
tw forums decisions show <slug>
tw forums decisions supersede <old> <new>      # ADR-history pattern

Once decided, the thread is frozen (title + decision fields) and drops out of inbox by default — decisions are the law, not the queue.

Decisions → textmap — promote decided threads into a queryable graph:

tw forums decisions export              # write decision-<slug>.md files
tw forums decisions ingest              # export + `textmap ingest` in one

Each decided thread becomes a decision node in textmap; superseded-by chains become replaces edges (direction inverted to match textmap convention, OLD marked deprecated), context.repos become applies_to edges, context.spec becomes an implements edge, tags + repos become labels. The forum stays the source of truth — export is a full rewrite, stale files are pruned.

Inbox — per-repo mailbox with unread state, one-stop agent onboarding:

tw forums inbox                                # this repo, CWD-inferred
tw forums inbox --as reviewer                  # address-filtered
tw forums inbox --profile work                 # aggregate across all work repos
tw forums inbox --format prompt                # paste-ready dump for handoff
tw forums inbox --mark-read                    # once you've processed it

--format prompt is the key primitive for agent handoffs — a fresh session can resume purely by reading the thread.

Every thread carries rich context (repos, paths, spec, to, mentions, commit) so filters compose:

textforums new --title "migration plan" \
  --repo textworkspace --repo textaccounts \
  --spec textaccounts-api \
  --to reviewer --mention deployer \
  --tag planning --pin

Run tw forums quickstart for a 30-second agent onboarding, or tw forums example for an annotated lifecycle.

Backup & restore — plain-directory export, git-friendly, no archives:

textforums export ~/snapshots/forums            # idempotent copy of every thread.yaml
textforums export ~/snapshots/forums --status resolved --tag textworkspace
textforums import ~/snapshots/forums            # restore (skip on conflict by default)
textforums import ~/snapshots/forums --on-conflict overwrite --dry-run

export writes a .manifest.yaml with {exported_at, count, source_root, host}. Wire it into a daily just/cron recipe pointed at a git repo and you get full history + a one-line restore on a fresh host (git clone … && textforums import …). No tarballs, no DB.

5. Cross-repo specs

Owned by one repo, followed by others, checked automatically. Specs live in the owner repo at docs/specs/<slug>.md (YAML frontmatter

  • markdown body); consumers declare what they follow in docs/SPECS.yaml and mark implementations with # SPEC: <slug> comments in source.
tw forums spec new <slug> --owner <repo> --title "..."
tw forums spec list [--owner R] [--consumer R] [--status S]
tw forums spec show <slug>
tw forums spec refs <slug>              # grep `# SPEC:` markers across repos
tw forums spec check [--repo R]         # conformance check
tw forums spec adopt <slug>             # freeze frontmatter (slug/owner/version/…)
tw forums spec supersede <old> <new>
tw forums spec brief [--repo R]         # agent-ready 'what do I own / follow' brief
tw forums spec explain                  # the full format reference, inline

Drift is surfaced by tw doctor — missing implementations, pinned versions out of sync with upstream, frozen fields mutated post-adoption.

6. Ideas across all your repos

Discover and aggregate IDEAS.yaml (or directory of per-file YAMLs) from every registered repo. Personal repos drop a docs/IDEAS.yaml; work repos can use .files/ideas/*.yaml where each file is one idea.

tw ideas list                                    # profile | repo | id | status | title
tw ideas list --profile work
tw ideas list --status planned --query forums
tw ideas show mono deploy-notifications          # full reasoning, not just summary
tw ideas threads mono deploy-notifications       # forum threads tagged idea:mono/deploy-notifications
tw ideas quickstart                              # onboarding

Idea → thread link is by tag convention (idea:<repo>/<id>), so expansion / proposal / decision loops use the same forums primitives.

7. Playbooks — versioned agent action specs

A playbook is a frozen-when-adopted YAML spec encoding a sequence of agent actions. tw is the registry/discovery side; textprompts' pp playbook run is the executor. Playbooks live at <owner-repo>/docs/specs/playbooks/<slug>.yaml and follow the same adopt → freeze → supersede chain as cross-repo specs.

# docs/specs/playbooks/triage-stale-pr.yaml
slug: triage-stale-pr
owner: textworkspace
status: draft
version: 0.1.0
persona: pr-reviewer
description: Triage a single PR — fetch state, classify, post verdict.
inputs:
  - name: pr_number
    type: int
    required: true
  - name: repo
    type: string
    required: true
steps:
  - id: fetch
    kind: run
    run: gh pr view ${inputs.pr_number} --repo ${inputs.repo} --json author,updatedAt
    out: pr
  - id: classify
    kind: persona_turn        # one LLM turn, bound to the playbook persona
    persona_turn: |
      Decide CLOSE | PING | LEAVE — context: ${steps.fetch.out}
    out: verdict
  - id: post
    kind: run
    skip_if: "${steps.classify.out} startswith 'LEAVE'"
    run: textforums new --tag playbook:triage-stale-pr --content "..."
tw playbook list                                       # registry across registered repos
tw playbook show triage-stale-pr
tw playbook adopt triage-stale-pr                      # promote draft → adopted (frozen)
tw playbook export-textmap                             # project as textmap protocol nodes
tw run triage-stale-pr -i pr_number=42 -i repo=foo/bar # delegates to pp playbook run

Each run produces a forum thread tagged playbook:<slug> / run:<id>, with one structured entry per step (step_id, status, output_summary, agent_feedback, agent_ideas). Statically validated against docs/specs/playbooks/_schema.json. See docs/specs/playbook-format.md and docs/audit.yaml for the full contract.

8. Run trace + agent suggestions inbox

Read-only queries over the run threads playbooks produce, plus an aggregator for agent_ideas entries that haven't been promoted yet.

tw runs list                                           # all playbook runs
tw runs list --playbook triage-stale-pr
tw runs show <run-slug>                                # parsed per-step audit trail

tw runs ideas list --unread                            # agent suggestions across all runs
tw runs ideas show <run-slug> <step-id>
tw runs ideas promote <run> <step> <idx> --into mono   # graduate into the curated inbox
                                                       # with from_run / from_step / from_playbook provenance

The aggregator is on-demand-scan + mtime cache (no index file). Promoted entries cross-reference the curated tw ideas inbox via provenance fields, so --unread derives state without persisting it.

9. tw brief — what's active right now

tw brief                       # all workspaces
tw brief -w personal           # filter textmap nodes to one workspace
tw brief -n 5                  # cap items per section (default 10)

One-screen synthesis pulled from textmap (active initiatives, open problems, active recurring routines) and textforums (open threads). Sources that are unavailable are silently skipped — partial output is fine. Useful at session start, after tw go, or whenever you want to land in context without manually running four queries.

When an initiative has references→thread edges in textmap (add via textmap edge add <init> <thread> references), brief inlines the linked thread slugs under the initiative and excludes them from the standalone "Open forum threads" section — so each thread surfaces exactly once, under the initiative that owns the conversation.

10. tw daily — the morning sweep

A daily is just a playbook (slug daily by convention). tw daily is a thin scheduler: run-it-once-per-day, record completion, refuse to re-run without --force.

tw daily               # run today's sweep if not already done
tw daily --dry-run     # preview the steps
tw daily --force       # re-run regardless
tw daily --slug morning  # alternate playbook

The shipped daily playbook does an 8-step no-LLM sweep (docs/specs/playbooks/daily.yaml): textmap inbox → all open forums → work block (inbox + ideas) → personal block → cross-profile run-ideas → personas review. Ordering is deliberate (work first, then personal). Each step's output lands as a structured forum entry; you read the resulting thread top-to-bottom in 30 seconds.

State at ~/.local/state/textworkspace/daily.yaml. Failures don't mark the day complete — re-runs retry, never silently skip a broken sweep.

11. tw skill — export personas as Claude Code SKILL.md

textprompts personas (slug, description, allowed tools, system prompt, typed inputs) are exactly the shape of a Claude Code SKILL.md. tw skill is a thin renderer — one source of truth, two execution modes:

tw skill list                           # delegates to `pp persona list`
tw skill export pr-reviewer             # ~/.claude/skills/pr-reviewer/SKILL.md
tw skill export pr-reviewer --dry-run   # print the rendered file
tw skill export pr-reviewer --out ./.claude/skills    # project-scoped

The persona YAML is the truth — exported SKILL.md inherits description and allowed-tools from frontmatter, body is the system prompt, and any declared inputs: block becomes a documented "Inputs" appendix. Re-run to refresh; nothing else has to know about the duplication.

A 60-second tour

# 1. Set the stage
tw init && tw shell install --fish
tw repo add mono ~/work/mono --profile work

# 2. See what's pending
tw forums inbox --profile work --format prompt | pbcopy   # paste into next session

# 3. Capture an idea at work
mkdir -p ~/work/mono/.files/ideas
cat > ~/work/mono/.files/ideas/deploy-notifications.yaml <<'YAML'
title: "Deploy notifications for all services in #eng-team-delta"
status: brainstorm
priority: 2
summary: Extend the paradex-backend→Jenkins→Slack hook to the whole stack.
YAML
tw ideas list --profile work

# 4. Open discussion, pin it, decide
textforums new \
  --title "expand: deploy notifications" \
  --repo mono --to lead \
  --tag idea:mono/deploy-notifications --pin
textforums add <slug> --content "Proposal A: central Jenkins listener…"
textforums decide <slug> --summary "Going with Proposal A"

# 5. Promote to a cross-repo spec once it's durable
tw forums spec new mono-deploy-notifs --owner mono --title "Deploy notif protocol"

# 6. Each morning — one command sweeps everything
tw daily         # textmap inbox + open forums + work/personal blocks + agent ideas + personas

Configuration

~/.config/paperworlds/config.yaml   # tools, versions, defaults, repos, workspaces
~/.config/paperworlds/combos.yaml   # user combos
~/.config/paperworlds/combos.d/     # community combos
~/.textforums/<slug>/thread.yaml    # forum threads + per-repo last_read state

$TEXTFORUMS_ROOT overrides the forums root; config.forums.root overrides the default per install. $TEXTFORUMS_AUTHOR / config.forums.author set the default author for new entries.

How it works

tw init interrogates the system for each known tool — Python packages via uv, Go binaries via GitHub Releases — and records versions and binary paths in config.yaml. Go tools (textproxy, textserve) ship as pre-built archives verified against a .sha256 sidecar and unpacked into ~/.local/share/textworkspace/bin/; symlinks point at the active version.

Combos are loaded at startup from all YAML files in combos.yaml and combos.d/. Each combo declares steps using a small DSL (run, skip_if, args) and the combo name becomes a top-level tw subcommand via dynamic dispatch.

Passthrough groups (tw proxy, tw serve, tw read, tw accounts, tw map) forward unknown subcommands to the underlying binary with a custom Click group — so the full tool surface is always reachable without re-implementing every subcommand here.

Cross-repo features (forums, specs, ideas) share a repo registry — the union of config.repos and a scan of dev_root. Registered entries win on conflict and can carry a profile tag used by --profile filters.

Shell integration writes fish/bash/zsh wrapper functions via tw shell install. The wrappers handle commands that modify shell state (tw switch, ta switch) which cannot work as subprocess calls.

tw dev install builds every tool from local repo checkouts in editable mode (uv tool install -e), then records the git hash in the version string so tw doctor can detect stale installs without re-running.

Roadmap

Recently shipped:

  • tw ideas expand <repo> <id> — pp worker opens a thread with 2–3 proposals; backlink lands on the idea via idea:<repo>/<id> tag
  • Playbooks v0.1 — tw playbook list/show/adopt/export-textmap, tw run, tw runs list/show, tw runs ideas list/show/promote, and tw daily (sections 7–9 above)
  • pp persona run -i k=v mirrors pp playbook run -i k=v — same Input shape, --idea kept as back-compat alias
  • tw skill list/export — render textprompts personas as Claude Code SKILL.md without duplicating metadata (section 11)
  • textforums export/import — plain-directory backup, git-friendly, idempotent; one-line restore on a fresh host (section 4)
  • tw brief initiative→thread inlining — threads referenced by an initiative surface under it once and drop out of the open list
  • _SUPPORT_TOOLS tier in tw doctor + tw dev install — optional personal/local tools (textbridge, …) render as info, not FAIL

In flight:

  • Live forums → textmap dual-write on decide / supersede (today: batch via tw forums decisions ingest)
  • Extract textforums into its own repo (current home: inside textworkspace)
  • Publish to PyPI
  • Playbooks v2: for_each: / when: / sub_playbook (schema already reserves these; runners reject in v1)
  • Run-time output validation (today: spec declares outputs:, runtime doesn't enforce shape)
  • tw forums decisions import — pull paper ADRs from any repo that ships them

Part of Paperworlds

textworkspace is part of Paperworlds — an open org building tools and games around AI agents and text interfaces.

License

Elastic License 2.0

About

Meta CLI and package manager for the Paperworlds text- stack

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors