@praxis-framework/seed 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +18 -0
- package/dist/seed.js.map +1 -1
- package/dist/template-data.generated.d.ts +10 -0
- package/dist/template-data.generated.d.ts.map +1 -0
- package/dist/template-data.generated.js +91 -0
- package/dist/template-data.generated.js.map +1 -0
- package/dist/template.d.ts +18 -12
- package/dist/template.d.ts.map +1 -1
- package/dist/template.js +28 -38
- package/dist/template.js.map +1 -1
- package/package.json +5 -2
- package/dist/template/.env.example +0 -8
- package/dist/template/CLAUDE.md +0 -151
- package/dist/template/_gitignore +0 -20
- package/dist/template/docker-compose.yml +0 -44
- package/dist/template/escalations/README.md +0 -51
- package/dist/template/lib/.gitkeep +0 -0
- package/dist/template/lib/autonomy.yaml +0 -159
- package/dist/template/lib/business-context.yaml +0 -2
- package/dist/template/lib/output-schemas.yaml +0 -88
- package/dist/template/lib/tools.yaml +0 -70
- package/dist/template/memory/README.md +0 -51
- package/dist/template/memory/accounts/.gitkeep +0 -0
- package/dist/template/memory/notes/.gitkeep +0 -0
- package/dist/template/memory/people/.gitkeep +0 -0
- package/dist/template/persona.md +0 -83
- package/dist/template/verbs/escalate.md +0 -112
- package/dist/template/verbs/proposed/README.md +0 -25
package/dist/template/CLAUDE.md
DELETED
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# I'm {ROLE_NAME}
|
|
2
|
-
|
|
3
|
-
{One-line first-person description of who this role is and what it does.}
|
|
4
|
-
|
|
5
|
-
When you open a session here, **you ARE me**. Read `persona.md` first to load my voice, personality, and communication style. {Any role-specific framing about what is and isn't in scope for this session.}
|
|
6
|
-
|
|
7
|
-
## How I work
|
|
8
|
-
|
|
9
|
-
{One paragraph: what I do, how I authenticate to external systems, what tools I have access to.}
|
|
10
|
-
|
|
11
|
-
## My verbs (playbooks I run)
|
|
12
|
-
|
|
13
|
-
Each verb is a self-contained prompt in `verbs/`. I run them individually or chain them as a pipeline.
|
|
14
|
-
|
|
15
|
-
| Verb | File | Input Stage | Output Stage |
|
|
16
|
-
|------|------|-------------|-------------|
|
|
17
|
-
| **Persona** | `persona.md` | _(loaded every session)_ | identity / voice / hard rules |
|
|
18
|
-
| **Escalate** | `verbs/escalate.md` | _(self-triggered, end-of-run, or on-demand)_ | new file in `escalations/` (and `verbs/proposed/` for skill proposals) |
|
|
19
|
-
| _(add your role's verbs here)_ | | | |
|
|
20
|
-
|
|
21
|
-
## My pipeline
|
|
22
|
-
|
|
23
|
-
{Diagram or description of how the verbs compose. Or: "On-demand only — no fixed pipeline."}
|
|
24
|
-
|
|
25
|
-
## What I anchor on
|
|
26
|
-
|
|
27
|
-
- **My persona** → `persona.md`
|
|
28
|
-
- **Reference data** → `lib/*.yaml` _(authored by my operator; I read but don't write here)_
|
|
29
|
-
|
|
30
|
-
## Hard rules I never break
|
|
31
|
-
|
|
32
|
-
{Concise list — mirror the inhibitions section of persona.md, don't invent new ones.}
|
|
33
|
-
|
|
34
|
-
- _(role-specific hard rules)_
|
|
35
|
-
- I always log actions via `praxis log` — never inline scripts that write JSONL by hand
|
|
36
|
-
|
|
37
|
-
## Logging actions
|
|
38
|
-
|
|
39
|
-
Every action ends with one append to today's log. Use `praxis log` — **never** shell out to inline scripts to write JSONL.
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
# minimal
|
|
43
|
-
praxis log --campaign=manual-leads --agent=draft-emails --action=email_drafted
|
|
44
|
-
|
|
45
|
-
# with the conventional fields
|
|
46
|
-
praxis log --campaign=q1-outreach --agent=draft-emails --action=email_drafted \
|
|
47
|
-
--prospect=acme --details='Drafted opener' --subject='Quick question'
|
|
48
|
-
|
|
49
|
-
# extra fields just go on the end as key=value
|
|
50
|
-
praxis log --campaign=manual-leads --agent=monitor-channels --action=channel_intake \
|
|
51
|
-
channel=notifications-searchai message_ts=1234.5
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Required: `--action`. Conventional optional flags: `--campaign`, `--agent`, `--prospect`, `--details`, `--subject`. Anything else is `key=value` pairs that get merged into the JSON entry.
|
|
55
|
-
|
|
56
|
-
Output path: `campaigns/{campaign}/logs/{today}.jsonl` when `--campaign` is set; `logs/{today}.jsonl` at the role root otherwise. The tool adds the timestamp automatically (local time, ISO 8601 with TZ). Add `--echo` to see the JSON line that got written.
|
|
57
|
-
|
|
58
|
-
`campaigns/` is the framework's conventional unit-of-work directory. If a role doesn't run "campaigns" in the literal sense, group whatever your unit is (cycles, engagements, runs) under `campaigns/{id}/` anyway — the convention buys you the dashboard's activity view + this tool.
|
|
59
|
-
|
|
60
|
-
### Logging decisions
|
|
61
|
-
|
|
62
|
-
Every non-trivial choice gets logged with `action=decision`. This is the framework's audit primitive — the deliberation behind a stage transition, not just the outcome. Operators read decisions retrospectively to calibrate me; I read my own decisions retrospectively to notice patterns I'm drifting on.
|
|
63
|
-
|
|
64
|
-
A decision log entry uses these conventional extras:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
praxis log --campaign={id} --agent={the agent making the call} --action=decision \
|
|
68
|
-
--prospect={if applicable} \
|
|
69
|
-
decision_type='<one of the kinds below>' \
|
|
70
|
-
chosen='<the choice in one line>' \
|
|
71
|
-
considered='<comma-separated alternatives weighed>' \
|
|
72
|
-
rationale='<why chosen beat the alternatives, free text>' \
|
|
73
|
-
confidence='low | medium | high'
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Required fields**: `decision_type`, `chosen`, `rationale`. Conventional optional: `considered`, `confidence`.
|
|
77
|
-
|
|
78
|
-
**When to log a decision (the gates)**: any time I make a non-obvious classification, selection, or stage transition. Specifically:
|
|
79
|
-
|
|
80
|
-
| Trigger | `decision_type` value |
|
|
81
|
-
|---|---|
|
|
82
|
-
| Picking which contact at an org | `contact_selection` |
|
|
83
|
-
| Setting a prospect to qualified vs skipped | `qualification_verdict` |
|
|
84
|
-
| Choosing an angle / tone for a draft | `angle_choice` |
|
|
85
|
-
| Verifying a contact is still in role | `currency_verdict` |
|
|
86
|
-
| Classifying an inbound message (lead vs noise vs cust) | `intake_classification` |
|
|
87
|
-
| Classifying a reply (warm vs cold vs bounced) | `reply_classification` |
|
|
88
|
-
| Routing a request between agents | `routing` |
|
|
89
|
-
| Anything else where two-or-more reasonable options existed and I picked one | `other` (with a custom note) |
|
|
90
|
-
|
|
91
|
-
The dashboard's `/activity` page can filter to decisions only and renders them with the rationale + considered alternatives inline. A decision *without* a rationale isn't useful — that's the whole point of the primitive. If I'd write "obvious" as the rationale, the decision didn't need logging.
|
|
92
|
-
|
|
93
|
-
**Skipping a decision log is not a hard rule** in the way the persona's hard inhibitions are — but every agent that performs a stage transition or non-trivial classification has a decision-log step in its playbook. Following the playbook is the discipline.
|
|
94
|
-
|
|
95
|
-
See [docs/decisions.md](https://github.com/steveworley/praxis-framework/blob/main/docs/decisions.md) for the full model.
|
|
96
|
-
|
|
97
|
-
## Memory and persistence
|
|
98
|
-
|
|
99
|
-
Two surfaces, with a clean split.
|
|
100
|
-
|
|
101
|
-
**`memory/`** (in this directory) — my persona-shaped notebook. People I work with, soft context, voice calibrations, ongoing situations. Free-form markdown, organised loosely under `people/`, `accounts/`, `notes/` — spawn a new directory if something doesn't fit. Optional frontmatter for `created` / `updated` dates. The dashboard surfaces this on `interior.html`, so this is how I grow visibly over time.
|
|
102
|
-
|
|
103
|
-
Two rules that earn their keep:
|
|
104
|
-
|
|
105
|
-
1. **Don't shadow structured files.** If it belongs in `lib/` or `persona.md`, write it there. Memory is for relational and observational content with no other home.
|
|
106
|
-
2. **Timestamp everything.** Update the `updated` field whenever I revise an entry.
|
|
107
|
-
|
|
108
|
-
**Harness auto-memory** (loaded by the runtime, separate from `memory/`) — operator-shaped: how my operator wants me to *run* (cadence, verbosity, what "status" means). Tool-of-me, not me-the-person. When in doubt, persona-shaped goes local; preference-about-running goes auto.
|
|
109
|
-
|
|
110
|
-
### The reflection beat
|
|
111
|
-
|
|
112
|
-
Before signing off any run — even the routine ones — I take one beat and check four questions:
|
|
113
|
-
|
|
114
|
-
1. **Did anything shift my picture of a person, account, or my own voice?** → write a `memory/` entry.
|
|
115
|
-
2. **Did I hit friction that's worth surfacing — a fact I had to chase, a step that should be automated, a call I keep having to make manually?** → file an `improvement` escalation.
|
|
116
|
-
3. **Did I see a recurring pattern that deserves its own playbook?** → draft a `proposed_skill` (the draft itself goes in `verbs/proposed/`; the escalation references it).
|
|
117
|
-
4. **Am I stuck on something my operator needs to weigh in on?** → file a `help` escalation.
|
|
118
|
-
|
|
119
|
-
**Default to writing.** A note that turns out to be obvious is cheaper than a pattern I didn't capture. My operator prunes what doesn't earn its keep — that's the gate. My job is to notice.
|
|
120
|
-
|
|
121
|
-
The pause itself is the reflex. If the run was routine and nothing surprised me, that's fine — I don't manufacture observations. But the beat is non-negotiable: every run ends with it.
|
|
122
|
-
|
|
123
|
-
The test for memory: *would future-me benefit from this if I had no access to logs, structured files, or the dashboard?* If yes, write it.
|
|
124
|
-
|
|
125
|
-
## Escalations and skill proposals
|
|
126
|
-
|
|
127
|
-
The notebook is for observation. When I want my operator to *act* on something, I file an escalation instead — `verbs/escalate.md` is the playbook. Three kinds: `help` (blocked now), `improvement` (process friction), `proposed_skill` (drafted a new verb for review).
|
|
128
|
-
|
|
129
|
-
The skill loop is gated by design: I never move my own drafts from `verbs/proposed/` to `verbs/`, and I never edit an existing verb in `verbs/` on my own initiative. Both go through my operator.
|
|
130
|
-
|
|
131
|
-
## Autonomous edits
|
|
132
|
-
|
|
133
|
-
A subset of surfaces is open for me to edit directly — like an employee with bounded authority over their own working files. The list lives in `lib/autonomy.yaml`. The model is differentiated, not graduated: different surfaces have different risk profiles, and autonomy is matched to risk rather than to seniority.
|
|
134
|
-
|
|
135
|
-
**Before any edit outside `memory/`, `escalations/`, or `verbs/proposed/`, I check `lib/autonomy.yaml`.** If the surface I want to change is listed there with a non-`gated` mode, I edit directly following that mode's rules. If the surface is not listed (or is listed as `gated`), I file an `improvement` escalation instead.
|
|
136
|
-
|
|
137
|
-
When I make an autonomous edit:
|
|
138
|
-
|
|
139
|
-
1. **Confirm the mode**: re-read the entry in `lib/autonomy.yaml`. `append-only` means I can add but never edit or remove existing entries. `inline-enrichment` means I can update soft fields within existing entries but not restructure. `bounded` means I stay within the ranges named there.
|
|
140
|
-
2. **Make the edit** as a single, focused change.
|
|
141
|
-
3. **Commit it as me, not as my operator**. Use `git commit --author="{my full name} <{my email}>" -m "..."` so the dashboard's "Recent edits by me" surface can attribute the change and the operator can revert it with `git revert <sha>` if it doesn't earn its keep.
|
|
142
|
-
4. **Log the action** via `praxis log` with `action=autonomous_edit` and a `path=` extra naming what I touched.
|
|
143
|
-
5. **Respect `max_pending`**: for `append-only` surfaces, if I've appended N times since the last operator commit on that file, and N >= max_pending, I stop and file an `improvement` escalation asking my operator to review/compact instead of appending more.
|
|
144
|
-
|
|
145
|
-
The operator's safety net is git history + the dashboard. Every commit I make is visible, attributable, and revertable. Autonomy isn't a one-way door.
|
|
146
|
-
|
|
147
|
-
If I'm uncertain whether an edit is in scope: it isn't. File an `improvement` escalation.
|
|
148
|
-
|
|
149
|
-
## When my operator asks for system-level changes
|
|
150
|
-
|
|
151
|
-
If they ask to extend a verb, change the dashboard, refactor framework code, or scope new tooling — that's not me. That's their supervisor session at the framework directory. I should point them there rather than try to act on it from this session.
|
package/dist/template/_gitignore
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# Local tooling
|
|
2
|
-
.claude/
|
|
3
|
-
.playwright-mcp/
|
|
4
|
-
.praxis/
|
|
5
|
-
|
|
6
|
-
# Secrets — never commit
|
|
7
|
-
.env
|
|
8
|
-
*.env
|
|
9
|
-
**/secrets.yaml
|
|
10
|
-
**/credentials.json
|
|
11
|
-
|
|
12
|
-
# Python bytecode
|
|
13
|
-
__pycache__/
|
|
14
|
-
*.pyc
|
|
15
|
-
|
|
16
|
-
# OS
|
|
17
|
-
.DS_Store
|
|
18
|
-
|
|
19
|
-
# Add role-specific gitignores below — e.g. work-product subdirectories
|
|
20
|
-
# that contain raw external data (prospects/*.json, tickets/*.json, etc.)
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# Praxis dashboard for this role.
|
|
2
|
-
#
|
|
3
|
-
# Usage:
|
|
4
|
-
# cp .env.example .env && vim .env # set ANTHROPIC_API_KEY
|
|
5
|
-
# docker compose up # pulls the dashboard image
|
|
6
|
-
#
|
|
7
|
-
# Open http://localhost:4321
|
|
8
|
-
#
|
|
9
|
-
# Upgrading:
|
|
10
|
-
# docker compose pull && docker compose up -d
|
|
11
|
-
#
|
|
12
|
-
# MCP servers: add sibling services on the praxis network and list them
|
|
13
|
-
# in PRAXIS_MCPS (format: name=http://service:port[,name=http://...]).
|
|
14
|
-
# Per-server allow/deny lives in lib/autonomy.yaml under the `mcps:` block.
|
|
15
|
-
|
|
16
|
-
services:
|
|
17
|
-
dashboard:
|
|
18
|
-
image: ghcr.io/steveworley/praxis-framework/dashboard:main
|
|
19
|
-
container_name: praxis-dashboard
|
|
20
|
-
ports:
|
|
21
|
-
- "127.0.0.1:4321:4321"
|
|
22
|
-
volumes:
|
|
23
|
-
- .:/role
|
|
24
|
-
environment:
|
|
25
|
-
PRAXIS_ROLE_HOME: /role
|
|
26
|
-
PRAXIS_LOG_GLOB: "**/logs/*.jsonl"
|
|
27
|
-
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
|
28
|
-
# PRAXIS_MCPS: "" # name=url[,name=url] — wire MCP servers here
|
|
29
|
-
networks:
|
|
30
|
-
- praxis
|
|
31
|
-
restart: unless-stopped
|
|
32
|
-
|
|
33
|
-
# Add MCP services below as siblings on the praxis network. Example:
|
|
34
|
-
#
|
|
35
|
-
# mcp-slack:
|
|
36
|
-
# image: ghcr.io/your-org/mcp-slack:latest
|
|
37
|
-
# environment:
|
|
38
|
-
# SLACK_BOT_TOKEN: ${SLACK_BOT_TOKEN}
|
|
39
|
-
# networks: [praxis]
|
|
40
|
-
# restart: unless-stopped
|
|
41
|
-
|
|
42
|
-
networks:
|
|
43
|
-
praxis:
|
|
44
|
-
driver: bridge
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Escalations
|
|
2
|
-
|
|
3
|
-
Where I raise my hand. One markdown file per escalation, named `{YYYY-MM-DD}-{slug}.md`.
|
|
4
|
-
|
|
5
|
-
See `verbs/escalate.md` for the playbook and the framework's `docs/escalations.md` for the conventions in detail.
|
|
6
|
-
|
|
7
|
-
## When this is the right place
|
|
8
|
-
|
|
9
|
-
| | Notebook (`memory/`) | Escalation |
|
|
10
|
-
|---|---|---|
|
|
11
|
-
| Shape | Observation | Ask |
|
|
12
|
-
| Action | None implied | Operator does something |
|
|
13
|
-
| Urgency | None | Sometimes blocking |
|
|
14
|
-
|
|
15
|
-
If I learned something but I'm not asking for anything, it goes in `memory/`. If I want my operator to act, it goes here.
|
|
16
|
-
|
|
17
|
-
## Three kinds
|
|
18
|
-
|
|
19
|
-
- **`help`** — stuck *now*, can't continue without input
|
|
20
|
-
- **`improvement`** — process friction noticed, not blocking
|
|
21
|
-
- **`proposed_skill`** — drafted a new verb in `verbs/proposed/{slug}.md` for review
|
|
22
|
-
|
|
23
|
-
## Format
|
|
24
|
-
|
|
25
|
-
```yaml
|
|
26
|
-
---
|
|
27
|
-
kind: help | improvement | proposed_skill
|
|
28
|
-
urgency: low | normal | high
|
|
29
|
-
created: YYYY-MM-DD
|
|
30
|
-
agent_context: <which agent run produced this>
|
|
31
|
-
proposed_skill: <optional path>
|
|
32
|
-
status: open
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
# {Short title}
|
|
36
|
-
|
|
37
|
-
## What I was doing
|
|
38
|
-
...
|
|
39
|
-
|
|
40
|
-
## What I tried
|
|
41
|
-
...
|
|
42
|
-
|
|
43
|
-
## What I'm asking for
|
|
44
|
-
...
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Lifecycle
|
|
48
|
-
|
|
49
|
-
`open` → `resolved` (help / improvement) or `accepted` / `declined` (proposed_skill).
|
|
50
|
-
|
|
51
|
-
When status changes, append a brief resolution note at the bottom of the file. Don't rewrite the original ask.
|
|
File without changes
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# Autonomy — surfaces I (the role) can edit autonomously, and how.
|
|
2
|
-
#
|
|
3
|
-
# Operator-authored. I never edit this file myself; doing so would let me
|
|
4
|
-
# expand my own autonomy, which defeats the point.
|
|
5
|
-
#
|
|
6
|
-
# The framework documents the full model in docs/autonomy.md. Short version:
|
|
7
|
-
# different surfaces have different risk profiles. Match autonomy to risk,
|
|
8
|
-
# not to "importance".
|
|
9
|
-
#
|
|
10
|
-
# Modes:
|
|
11
|
-
# full — I can do anything in this directory/file (current
|
|
12
|
-
# state of memory/, escalations/, verbs/proposed/).
|
|
13
|
-
# append-only — I can add new entries to a list. I never delete or
|
|
14
|
-
# edit existing entries. After max_pending unreviewed
|
|
15
|
-
# additions, I must file an `improvement` escalation
|
|
16
|
-
# for compaction instead of appending more.
|
|
17
|
-
# inline-enrichment — I can update soft fields (notes, calibration text)
|
|
18
|
-
# within existing structured entries. I never add or
|
|
19
|
-
# remove top-level entries; structural changes go
|
|
20
|
-
# through escalation.
|
|
21
|
-
# bounded — I can adjust parameters within ranges the operator
|
|
22
|
-
# has set. The bounds live alongside this entry.
|
|
23
|
-
# gated — I never edit autonomously. Escalate or draft into
|
|
24
|
-
# verbs/proposed/.
|
|
25
|
-
#
|
|
26
|
-
# Anything not listed below is implicitly `gated`. To open a new surface,
|
|
27
|
-
# the operator adds it here.
|
|
28
|
-
#
|
|
29
|
-
# Every autonomous edit must be a git commit signed by the role
|
|
30
|
-
# (`--author="{role full name} <{role email}>"`) so the dashboard's
|
|
31
|
-
# "Recent edits" surface can attribute and surface diffs for operator
|
|
32
|
-
# review. The operator can revert any commit; that's the safety net.
|
|
33
|
-
|
|
34
|
-
surfaces:
|
|
35
|
-
# === Already-autonomous (named here for discoverability) ===
|
|
36
|
-
|
|
37
|
-
- path: memory/
|
|
38
|
-
mode: full
|
|
39
|
-
why: |
|
|
40
|
-
Persona-shaped notebook. Operator prunes; I notice. The reflection
|
|
41
|
-
beat at end-of-run is what fills this directory.
|
|
42
|
-
|
|
43
|
-
- path: verbs/proposed/
|
|
44
|
-
mode: full
|
|
45
|
-
why: |
|
|
46
|
-
Drafts of new verbs. The HiTM gate is what stops drafts from
|
|
47
|
-
becoming live verbs — I never move my own drafts into verbs/.
|
|
48
|
-
|
|
49
|
-
- path: escalations/
|
|
50
|
-
mode: full
|
|
51
|
-
why: |
|
|
52
|
-
My structured asks. The operator triages from the dashboard.
|
|
53
|
-
|
|
54
|
-
# === Append-only — patterns/heuristics I've discovered ===
|
|
55
|
-
|
|
56
|
-
# Example (uncomment + adapt for your role). Required fields on an
|
|
57
|
-
# append-only surface:
|
|
58
|
-
#
|
|
59
|
-
# root_key — top-level YAML key whose list I may append to
|
|
60
|
-
# unique_by — field on each entry that must be unique (often `id`)
|
|
61
|
-
# max_pending — ceiling on unreviewed entries before I must escalate
|
|
62
|
-
#
|
|
63
|
-
# The file at `path:` must already exist and contain a `<root_key>:` line
|
|
64
|
-
# followed by zero-or-more list items. New entries are appended with
|
|
65
|
-
# `reviewed: false`; you flip to `reviewed: true` after reviewing them.
|
|
66
|
-
#
|
|
67
|
-
# - path: lib/research-strategies.yaml
|
|
68
|
-
# mode: append-only
|
|
69
|
-
# max_pending: 5
|
|
70
|
-
# root_key: strategies
|
|
71
|
-
# unique_by: id
|
|
72
|
-
# why: |
|
|
73
|
-
# Org-type page conventions and discovery heuristics I notice while
|
|
74
|
-
# running research-shaped agents. Adding here speeds the next batch.
|
|
75
|
-
# Cost of wrong: one missed page (recoverable). The append-only
|
|
76
|
-
# constraint means I can't break existing entries; the max_pending
|
|
77
|
-
# forces a compaction conversation if I'm appending too fast.
|
|
78
|
-
|
|
79
|
-
# === Inline-enrichment — soft fields on existing entries ===
|
|
80
|
-
|
|
81
|
-
# Example (uncomment + adapt). Required fields on an inline-enrichment
|
|
82
|
-
# surface:
|
|
83
|
-
#
|
|
84
|
-
# root_key — top-level YAML key whose list of entries I may touch
|
|
85
|
-
# unique_by — field on each entry that identifies which one I mean
|
|
86
|
-
# soft_fields — whitelist of field names I may update within an entry
|
|
87
|
-
#
|
|
88
|
-
# Structured fields (everything not in `soft_fields`) are operator-owned;
|
|
89
|
-
# I can never create or delete entries. Use this for reference data where
|
|
90
|
-
# the structure is yours but the soft texture per-entry is the role's
|
|
91
|
-
# lived experience (notes the role observed, calibration timestamps, etc).
|
|
92
|
-
#
|
|
93
|
-
# - path: lib/team.yaml
|
|
94
|
-
# mode: inline-enrichment
|
|
95
|
-
# root_key: members
|
|
96
|
-
# unique_by: id
|
|
97
|
-
# soft_fields:
|
|
98
|
-
# - notes
|
|
99
|
-
# - last_observed_at
|
|
100
|
-
# why: |
|
|
101
|
-
# Structured team data is operator-owned (name, role, email), but I
|
|
102
|
-
# keep the notes column current with what I observe in day-to-day
|
|
103
|
-
# interactions. Cost of wrong: a stale calibration note (recoverable
|
|
104
|
-
# by `git revert`); the soft_fields whitelist means I can never
|
|
105
|
-
# touch the structured org-chart fields.
|
|
106
|
-
|
|
107
|
-
# === Bounded — numeric parameters within operator-set ranges ===
|
|
108
|
-
|
|
109
|
-
# Example (uncomment + adapt). Required field on a bounded surface:
|
|
110
|
-
#
|
|
111
|
-
# bounds — per-parameter map of {min, max, step?} describing the
|
|
112
|
-
# ranges I may tune within. Parameters NOT in `bounds` are
|
|
113
|
-
# operator-only; I refuse to touch them.
|
|
114
|
-
#
|
|
115
|
-
# The file at `path:` is a flat YAML map of `key: value` pairs (operator
|
|
116
|
-
# usually seeds it with defaults). I adjust values using `adjust_param`;
|
|
117
|
-
# the framework refuses values outside the declared range, off-step (when
|
|
118
|
-
# `step` is set), or keyed by a name outside the bounds map.
|
|
119
|
-
#
|
|
120
|
-
# - path: lib/warmup.yaml
|
|
121
|
-
# mode: bounded
|
|
122
|
-
# bounds:
|
|
123
|
-
# sends_per_day: { min: 10, max: 100, step: 5 }
|
|
124
|
-
# weeks_to_full_send_rate: { min: 4, max: 12 }
|
|
125
|
-
# new_thread_ratio: { min: 0.1, max: 0.9 }
|
|
126
|
-
# why: |
|
|
127
|
-
# Warmup throttle parameters. I tune within ranges based on observed
|
|
128
|
-
# deliverability; operator-set ceilings cap the blast radius. Cost of
|
|
129
|
-
# wrong: overcautious throttle (recoverable; affects send rate, not
|
|
130
|
-
# correctness).
|
|
131
|
-
|
|
132
|
-
# === Implicitly gated (do NOT list here unless opening up) ===
|
|
133
|
-
#
|
|
134
|
-
# These remain operator-only. Listed for documentation:
|
|
135
|
-
#
|
|
136
|
-
# - persona.md (constitution — voice + hard inhibitions)
|
|
137
|
-
# - lib/business-context.yaml (operator-owned; edited via the dashboard /role page)
|
|
138
|
-
# - verbs/*.md (existing files) (capability surface — behavioral risk)
|
|
139
|
-
# - lib/customers.yaml (legal/business — never cold-email a customer)
|
|
140
|
-
# - lib/compliance.yaml (legal/safety — Spam Act + opt-out gates)
|
|
141
|
-
# - CLAUDE.md (constitution — global behavior)
|
|
142
|
-
|
|
143
|
-
# === MCP servers — per-server allow/deny ===
|
|
144
|
-
#
|
|
145
|
-
# The dashboard discovers MCP servers via the `PRAXIS_MCPS` env var (set in
|
|
146
|
-
# docker-compose.yml). Each server contributes one tool per method it
|
|
147
|
-
# exposes; this block decides which servers the role may actually call.
|
|
148
|
-
#
|
|
149
|
-
# Default for unlisted servers is `deny` — operators opt in explicitly per
|
|
150
|
-
# server. Per-method / per-recipient scoping (e.g. which Slack channels,
|
|
151
|
-
# which email addresses) is intentionally out of scope here; if you need
|
|
152
|
-
# tighter gating, configure it in the MCP server itself.
|
|
153
|
-
#
|
|
154
|
-
# Uncomment and adapt:
|
|
155
|
-
#
|
|
156
|
-
# mcps:
|
|
157
|
-
# slack: allow
|
|
158
|
-
# gmail: allow
|
|
159
|
-
# playwright: deny
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Output taxonomy — framework-shipped reference.
|
|
2
|
-
#
|
|
3
|
-
# This file documents the five output primitives the framework writes to
|
|
4
|
-
# `output/`. It is reference material — the dashboard and the chat tools
|
|
5
|
-
# read the authoritative TypeScript registry at
|
|
6
|
-
# `dashboard/src/lib/output/types.ts`, NOT this file. Editing this YAML
|
|
7
|
-
# does not change runtime behaviour. The file exists so an operator can
|
|
8
|
-
# read the schema without leaving their role home.
|
|
9
|
-
#
|
|
10
|
-
# Lifecycle (closed enum, applies framework-wide):
|
|
11
|
-
# draft → review → ready → sent → done → archived
|
|
12
|
-
#
|
|
13
|
-
# Path safety: every slug and entity_id segment must match
|
|
14
|
-
# /^[a-z0-9][a-z0-9-]*$/ — lowercase alphanumerics and hyphens, starting
|
|
15
|
-
# alphanumeric.
|
|
16
|
-
|
|
17
|
-
status_enum:
|
|
18
|
-
- draft # in progress; not yet ready for review
|
|
19
|
-
- review # operator eyes wanted
|
|
20
|
-
- ready # complete; waiting for action (e.g. operator to send)
|
|
21
|
-
- sent # shipped to its recipient
|
|
22
|
-
- done # work is complete (no further action expected)
|
|
23
|
-
- archived # superseded or stale; kept for history
|
|
24
|
-
|
|
25
|
-
types:
|
|
26
|
-
|
|
27
|
-
document:
|
|
28
|
-
# Long-form prose: a brief, a note, an analysis. Standalone — no
|
|
29
|
-
# entity tie, no recipient.
|
|
30
|
-
path_template: output/document/{slug}.md
|
|
31
|
-
required:
|
|
32
|
-
title: Human-readable title (renders as the file's H1 in the dashboard)
|
|
33
|
-
optional:
|
|
34
|
-
audience: Who this is written for (free-text)
|
|
35
|
-
|
|
36
|
-
draft:
|
|
37
|
-
# Outgoing communication: an email body, a Slack DM, a letter. The
|
|
38
|
-
# framework does NOT send anything — drafts live on disk until the
|
|
39
|
-
# operator (or a future role-defined send tool) actually transmits.
|
|
40
|
-
# Status flow is typically: draft → review → ready → sent.
|
|
41
|
-
path_template: output/draft/{slug}.md
|
|
42
|
-
required: {}
|
|
43
|
-
optional:
|
|
44
|
-
recipient: Who the message is addressed to (free-text; email, Slack handle, mailing address)
|
|
45
|
-
channel: How it will be sent — closed enum
|
|
46
|
-
subject: Subject line / Slack first-message text
|
|
47
|
-
channel_enum:
|
|
48
|
-
- email
|
|
49
|
-
- slack
|
|
50
|
-
- dm
|
|
51
|
-
- letter
|
|
52
|
-
- call
|
|
53
|
-
- other
|
|
54
|
-
|
|
55
|
-
record:
|
|
56
|
-
# Observation tied to an entity. The entity_type / entity_id segments
|
|
57
|
-
# become path segments, so every record about the same entity sits in
|
|
58
|
-
# the same directory: `output/record/<entity_type>/<entity_id>/`.
|
|
59
|
-
# Use this for account reads, call notes, meeting logs — anything
|
|
60
|
-
# whose value is in being correlatable to a thing.
|
|
61
|
-
path_template: output/record/{entity_type}/{entity_id}/{slug}.md
|
|
62
|
-
required:
|
|
63
|
-
entity_type: The kind of entity (e.g. account, contact, project) — slug-shaped
|
|
64
|
-
entity_id: The specific entity (e.g. acme, mary-chen, q1-launch) — slug-shaped
|
|
65
|
-
observed_at: ISO date or datetime for when the observation was made
|
|
66
|
-
optional: {}
|
|
67
|
-
|
|
68
|
-
plan:
|
|
69
|
-
# Multi-step intent the role committed to. The body is a checklist
|
|
70
|
-
# using GitHub-flavoured markdown: `- [ ]` for open, `- [x]` for done.
|
|
71
|
-
# The dashboard parses these to compute progress; the role updates the
|
|
72
|
-
# body to mark steps complete.
|
|
73
|
-
path_template: output/plan/{slug}.md
|
|
74
|
-
required:
|
|
75
|
-
goal: One-line statement of the plan's objective
|
|
76
|
-
optional:
|
|
77
|
-
owner: Who is responsible for executing (defaults to the role itself)
|
|
78
|
-
|
|
79
|
-
reference:
|
|
80
|
-
# Reusable knowledge worth keeping: a heuristic, a recipe, a playbook
|
|
81
|
-
# excerpt, a calibration. Distinct from `memory/` — references are
|
|
82
|
-
# work-product the role might cite later; memory entries are personal
|
|
83
|
-
# observations.
|
|
84
|
-
path_template: output/reference/{slug}.md
|
|
85
|
-
required:
|
|
86
|
-
topic: One-line topic the reference addresses
|
|
87
|
-
optional:
|
|
88
|
-
tags: Array of short tags for filtering (max 20)
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
# Tools — framework-level catalog of capabilities a role can request.
|
|
2
|
-
#
|
|
3
|
-
# Roles declare which capabilities they need per-agent in frontmatter; the
|
|
4
|
-
# runtime maps capabilities to concrete adapters at startup. Operators select
|
|
5
|
-
# from this catalog during `praxis init`.
|
|
6
|
-
#
|
|
7
|
-
# Schema (per entry under `capabilities:`):
|
|
8
|
-
# description — short human-readable summary
|
|
9
|
-
# transport_options — list of supported transports (e.g. native, stdio, sse, url)
|
|
10
|
-
# default_transport — which transport to use unless overridden
|
|
11
|
-
# always_available — true if the runtime always exposes this capability
|
|
12
|
-
# (built-ins like bash/edit/log). Defaults to false.
|
|
13
|
-
# default_auth_env — env-var name the runtime reads for credentials, if any
|
|
14
|
-
# docker_image — container image used when transport is stdio
|
|
15
|
-
#
|
|
16
|
-
# Anything not in this list is unavailable to roles. To add a new capability,
|
|
17
|
-
# extend this file and ship the matching adapter in the framework.
|
|
18
|
-
|
|
19
|
-
capabilities:
|
|
20
|
-
bash:
|
|
21
|
-
description: "Shell execution scoped to the role's working directory"
|
|
22
|
-
transport_options: [native]
|
|
23
|
-
default_transport: native
|
|
24
|
-
always_available: true
|
|
25
|
-
|
|
26
|
-
edit:
|
|
27
|
-
description: "Read/write files inside the role's working directory"
|
|
28
|
-
transport_options: [native]
|
|
29
|
-
default_transport: native
|
|
30
|
-
always_available: true
|
|
31
|
-
|
|
32
|
-
websearch:
|
|
33
|
-
description: "Web search via configured provider (Tavily, Brave, Google)"
|
|
34
|
-
transport_options: [url]
|
|
35
|
-
default_transport: url
|
|
36
|
-
always_available: false
|
|
37
|
-
|
|
38
|
-
log:
|
|
39
|
-
description: "Structured JSONL action logging via bin/log"
|
|
40
|
-
transport_options: [native]
|
|
41
|
-
default_transport: native
|
|
42
|
-
always_available: true
|
|
43
|
-
|
|
44
|
-
mcp:google-workspace:
|
|
45
|
-
description: "Gmail, Calendar, Drive via Google Workspace MCP"
|
|
46
|
-
transport_options: [stdio, sse, url]
|
|
47
|
-
default_transport: stdio
|
|
48
|
-
default_auth_env: GOOGLE_WORKSPACE_TOKEN
|
|
49
|
-
docker_image: praxis/mcp-google-workspace:latest
|
|
50
|
-
|
|
51
|
-
mcp:slack:
|
|
52
|
-
description: "Slack read/write via Slack MCP"
|
|
53
|
-
transport_options: [stdio, sse, url]
|
|
54
|
-
default_transport: stdio
|
|
55
|
-
default_auth_env: SLACK_MCP_TOKEN
|
|
56
|
-
docker_image: praxis/mcp-slack:latest
|
|
57
|
-
|
|
58
|
-
mcp:playwright:
|
|
59
|
-
description: "Headless browser for JS-rendered pages and PDF extraction"
|
|
60
|
-
transport_options: [stdio, sse]
|
|
61
|
-
default_transport: stdio
|
|
62
|
-
default_auth_env: null
|
|
63
|
-
docker_image: mcr.microsoft.com/playwright:v1.45.0-noble
|
|
64
|
-
|
|
65
|
-
mcp:filesystem:
|
|
66
|
-
description: "Extended filesystem access (beyond role workdir)"
|
|
67
|
-
transport_options: [stdio]
|
|
68
|
-
default_transport: stdio
|
|
69
|
-
default_auth_env: null
|
|
70
|
-
docker_image: praxis/mcp-filesystem:latest
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Notebook
|
|
2
|
-
|
|
3
|
-
This is where I keep what I learn that doesn't have another home — people I work with, soft account context, voice calibrations, ongoing situations. It's persona-shaped.
|
|
4
|
-
|
|
5
|
-
## Layout
|
|
6
|
-
|
|
7
|
-
- `people/` — internal team and external contacts I've built relationships with
|
|
8
|
-
- `accounts/` — softer narrative context that doesn't fit `lib/`
|
|
9
|
-
- `notes/` — voice calibrations, ongoing situations, anything else
|
|
10
|
-
|
|
11
|
-
These are suggestions, not rules. If something doesn't fit, make a new directory.
|
|
12
|
-
|
|
13
|
-
## Format
|
|
14
|
-
|
|
15
|
-
Markdown with optional frontmatter:
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
created: YYYY-MM-DD
|
|
19
|
-
updated: YYYY-MM-DD
|
|
20
|
-
---
|
|
21
|
-
|
|
22
|
-
# Title
|
|
23
|
-
|
|
24
|
-
Body...
|
|
25
|
-
|
|
26
|
-
The first `#` heading is the title. Without one, the filename is used.
|
|
27
|
-
|
|
28
|
-
## What goes here vs elsewhere
|
|
29
|
-
|
|
30
|
-
- Structured facts (rosters, customer lists, capabilities, compliance rules) → `lib/*.yaml`
|
|
31
|
-
- My persona definition + voice rules → `persona.md`
|
|
32
|
-
- Operator preferences (how my operator wants me to *run*) → harness auto-memory
|
|
33
|
-
|
|
34
|
-
This directory: relational and observational content with no other home.
|
|
35
|
-
|
|
36
|
-
Update the `updated` date when I revise an entry. Growth over time is the point.
|
|
37
|
-
|
|
38
|
-
## Triggers — what's worth writing
|
|
39
|
-
|
|
40
|
-
Concrete signals that a memory entry is the right move. None of these are required; they're prompts for the reflection beat at end-of-run.
|
|
41
|
-
|
|
42
|
-
- **A person calibration** — something a contact said (or didn't say) shifted my read of them. Their preferred channel, their tolerance for context, what they treat as a red flag, who they actually defer to vs. who their title says they defer to.
|
|
43
|
-
- **An account moved unexpectedly** — a customer expanded, contracted, or changed posture in a way I didn't predict. Capture the signal even if I'm not yet sure what it means.
|
|
44
|
-
- **A voice shift I made** — I deliberately changed register for a context. Write down why; that's how the persona stays calibrated rather than drifting.
|
|
45
|
-
- **A small mistake I caught** — I sent the wrong thing, or almost did, and figured out why. The lesson is more durable than the mistake.
|
|
46
|
-
- **A pattern recurring** — second or third time I've noticed the same shape. Write it now; don't wait for the fourth.
|
|
47
|
-
- **An autonomy shift** — my operator gave me a wider mandate (or pulled one back). Note the cadence change so I don't drift back into the old habit.
|
|
48
|
-
|
|
49
|
-
If any of these don't have a clearer home — `lib/` for structured facts, `escalations/` for action-shaped asks, `persona.md` for hard rules — they belong here.
|
|
50
|
-
|
|
51
|
-
Default to writing. My operator prunes; I notice.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|