@aethrekh/pisces-core
Pisces Core — domain-agnostic learning engine for Pi Coding Agent
Package details
Install @aethrekh/pisces-core from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@aethrekh/pisces-core- Package
@aethrekh/pisces-core- Version
0.3.0-beta.0- Published
- Aug 21, 2026
- Downloads
- 848/mo · 84/wk
- Author
- aethrekh
- License
- UNLICENSED
- Types
- extension
- Size
- 1.4 MB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./src/extensions/workspace-gate.ts",
"./src/attempt-capture.ts",
"./src/extensions/integrity-guard.ts",
"./src/extensions/progress-tracker.ts",
"./src/extensions/input-revamp.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@aethrekh/pisces-core
Domain-agnostic learning engine for Pi Coding Agent. Provides rubric-driven evaluation, integrity enforcement, attempt history, and a teaching persona that adapts to any subject — not just CS.
This package is the foundation. Domain packages (pisces-cs, pisces-sysdesign, etc.) sit on top of it, contributing subject-specific rubrics without modifying the engine itself.
What it does
| Capability | How |
|---|---|
| Teaching persona | SYSTEM.md injected as the Pisces AI identity on every session |
| Workspace gating | Skills and themes only activate inside a .pisces-marked directory |
| Attempt evaluation | /attempt command feeds submitted work + rubric + gap history to the model |
| Integrity enforcement | on_input extension blocks code-generation requests during graded evaluations |
| Gap memory | Attempt history persists across sessions; recurring weaknesses surface automatically |
| Burnout nudges | Session length tracking with configurable break reminders |
| Custom input bar | Replaces Pi's default prompt with a framed bar showing workspace state and session cost |
Installation
pi install npm:@aethrekh/pisces-core
Alternatively, for local development:
pi install /path/to/packages/core
The postinstall script copies SYSTEM.md to ~/.pi/agent/APPEND_SYSTEM.md (persona injection) and installs the pisces-editorial-noir theme to ~/.pi/agent/themes/.
Quick start
# 1. Install (or add to local Pi settings)
pi install npm:@aethrekh/pisces-core
pi install npm:@aethrekh/pisces-cli # workspace commands (/pisces)
# 2. Navigate to your workspace and activate
cd ~/my-project
pi
/pisces --activate
# 3. Submit work for evaluation
/attempt function twoSum(nums, target) { ... }
Workspace activation
Skills and the /attempt command are off by default. They activate only when Pi is started from a directory that has a .pisces marker file at or above it.
~/my-project/ ← .pisces lives here
├── module-1/
│ └── lab1/ ← start Pi here; workspace-gate walks up and activates
└── module-2/
Workspace state is detected once at resources_discover (before session start) and cached for the session. Pi's working directory is fixed at startup — a mid-session cd does not re-trigger detection.
Use @aethrekh/pisces-cli for the /pisces command that creates and removes .pisces markers.
/attempt command
The primary user-facing command. Submits work to the model for rubric-driven evaluation.
/attempt <your code or text>
/attempt --type essay <your text>
/attempt --goal "implement binary search" <your code>
Flags:
| Flag | Description |
|---|---|
--type code|essay|generic |
Override the inferred attempt type (inferred from content by default) |
--goal "description" |
Describe what you were trying to achieve (stored in attempt history) |
What happens:
- Workspace state is checked — redirects to
/pisces --activateif no.piscesfound. - The active rubric is loaded from
.pisces/rubric.json(domain rubric) or the built-ingeneric-attemptrubric. - Recent gap history is fetched from
~/.pisces/attempt-history.json. - Rubric + gaps + submitted content are injected into the conversation.
- The model evaluates and scores against the rubric criteria.
- The attempt record (without the score — scoring is model-side) is written to history.
Rubric resolution
The calibration engine searches for a rubric in this order:
| Priority | Path | Source |
|---|---|---|
| 1 | .pisces/rubric.json (workspace-relative) |
Dropped by a domain package on activation |
| 2 | Built-in generic-attempt/rubric.json |
Bundled with pisces-core |
When no domain rubric is present, the built-in five-criterion rubric is used:
| Criterion | Weight |
|---|---|
| Functional Correctness & Robustness | 30% |
| Conceptual Understanding | 25% |
| Code Quality & Readability | 20% |
| Design, Modularity & Algorithms | 15% |
| Documentation & Reflection | 10% |
Extensions
Five extensions run automatically. All are gated behind workspace activation except where noted.
workspace-gate — resources_discover
Controls which skill and theme paths Pi discovers at session start. Returns skillPaths pointing at the bundled skills directory only when a .pisces marker is found. This is the sole gating mechanism — no .pisces, no skills.
attempt-capture — session_start
Registers the /attempt Pi command. See the command section above.
integrity-guard — on_input
Monitors every message for academic integrity risk. Two guard layers:
- General patterns — phrases like "write the complete solution for my assignment" or "do my homework" trigger a redirect to guided-learning mode.
- Graded-skill routing — within a
gradedSkillssession (e.g. immediately after/attempt), code-generation requests like "fix this" or "rewrite this" are blocked.
Risk levels: none → low → medium → high. Only high produces a hard redirect; lower levels inject a warning comment into the context.
The active safeSkills and gradedSkills lists come from the loaded RubricSpec.integrityProfile. Domain packages can override these via setIntegrityProfile().
progress-tracker — on_session_end
Tracks session duration and skill usage. At session end:
- If
productivity.burnout_nudgesis enabled and the session exceededsession_warning_minutes, surfaces a break reminder. - If
productivity.weekly_summaryis enabled, shows a compact weekly activity table.
input-revamp — session_start
Replaces Pi's default input bar with a framed prompt bar:
╭─ 🐠 Pisces · active ────────────────────────── 5.2% · $0.015 · 8.3K out ─╮
│ › your message here │
╰──────────────────────────────────────────────── T3 · $0.008 · OUT 4.1K ───╯
Features: typing-speed whitening on the border, animated thinking VU-meter, submit flash, real-time session cost and token count.
Configuration
Config is loaded via a priority chain — first match wins:
.pisces.jsonin the current working directory~/.pi/pisces.json~/.config/pisces/config.json- Built-in defaults
{
"student": {
"name": "Alex",
"year_of_study": 2,
"timezone": "America/New_York"
},
"explanations": {
"default_depth": "intermediate",
"prefer_visuals": true,
"use_analogies": true
},
"integrity": {
"enabled": true,
"strictness": "balanced"
},
"productivity": {
"burnout_nudges": true,
"session_warning_minutes": 180,
"weekly_summary": true
}
}
Full schema: config/schema.json
Defaults: config/defaults.json
Config fields
student
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | — | First name for personalised greetings |
year_of_study |
integer (1–8) | 1 |
Year of study for depth calibration |
timezone |
string | — | Timezone string, e.g. America/New_York |
explanations
| Field | Type | Default | Description |
|---|---|---|---|
default_depth |
beginner|intermediate|advanced |
intermediate |
Explanation depth when not specified |
prefer_visuals |
boolean | true |
Prefer diagrams for structural concepts |
use_analogies |
boolean | true |
Include real-world analogies |
integrity
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Enable the integrity guard |
strictness |
strict|balanced|relaxed |
balanced |
Aggressiveness of integrity pattern matching |
productivity
| Field | Type | Default | Description |
|---|---|---|---|
burnout_nudges |
boolean | true |
Show break reminders after long sessions |
session_warning_minutes |
integer | 180 |
Minutes before a break reminder appears |
weekly_summary |
boolean | true |
Show a weekly activity table at session end |
Attempt history
Attempt records are stored in ~/.pisces/attempt-history.json. The file is capped at 200 records (oldest pruned first). Each record:
{
"id": "m5ix2kfz9",
"timestamp": "2026-07-03T10:22:00.000Z",
"skillName": "attempt",
"attemptType": "code",
"goal": "implement binary search tree",
"gaps": [],
"strengths": [],
"score": null
}
The gaps and strengths arrays are populated after the model evaluates the attempt. On subsequent /attempt invocations, a compact deduplicated summary of unresolved gaps is injected into the conversation so the model can check for recurring weaknesses.
Public API (for domain packages)
@aethrekh/pisces-core exports the following for use by domain packages and pisces-cli:
import {
// Workspace detection
findWorkspace, // (cwd: string) => WorkspaceResult
getWorkspaceState, // () => WorkspaceResult (cached singleton)
syncWorkspaceState, // (cwd: string) => WorkspaceResult (update cache)
// Config
loadConfig, // () => PiscesConfig
deepMerge, // (base, override) => merged config
getConfigSearchPaths, // () => string[]
// Lifecycle hooks (for custom integrations)
onLoad,
onStartup,
onDirectoryChange,
onSkillCall,
onMidSession,
onSessionEnd,
createSessionState,
// Metadata
PACKAGE_VERSION,
SKILLS,
isValidSkill,
} from "@aethrekh/pisces-core";
For domain package authors
A domain package extends Pisces Core by:
- Providing a rubric — ship a
rubric.jsonvalidated against@aethrekh/rubric-schema. On workspace activation, write it to.pisces/rubric.jsonin the learner's workspace root. - Registering its skills — declare additional skills in
pi-package.yaml. Skills are gated byworkspace-gate.tsautomatically viaresources_discover. - Optionally setting the integrity profile — call
setIntegrityProfile({ safeSkills, gradedSkills })frompisces-core/integrity-guardto override the default routing rules.
Pisces Core resolves the domain rubric at /attempt time with no further configuration needed.
Package scripts
pnpm build # Compile src/ → dist/ and scripts/ → dist/scripts/
pnpm test # Run Jest test suite
pnpm test:coverage # With coverage (70% branch / 80% line thresholds)
pnpm typecheck # Type-check without emit
pnpm lint # ESLint over src/ and scripts/
pnpm check # typecheck + lint + test:coverage (CI gate)
pnpm validate # Validate package.json, pi-package.yaml, and skill frontmatter
pnpm pack # Bundle into dist/pack/ and dist/*.tar.gz
pnpm release # Cut a release: bump version, update CHANGELOG, tag, pack
Architecture
packages/core/
├── SYSTEM.md # Pisces teaching persona (Pi system prompt)
├── pi-package.yaml # Pi runtime manifest
├── config/
│ ├── schema.json # Config schema
│ └── defaults.json # Default values
└── src/
├── index.ts # Public API + lifecycle hooks
├── pi-adapter.ts # Isolation layer for all Pi SDK calls
├── workspace-detector.ts # .pisces discovery + singleton cache
├── attempt-capture.ts # /attempt Pi command
├── calibration-engine.ts # Rubric loading + feedback context builder
├── correction-memory.ts # Attempt history read/write
├── memory-policy.ts # Write/inject validation (anti-softening)
├── postinstall.ts # Copies SYSTEM.md + theme on install
├── extensions/
│ ├── workspace-gate.ts # resources_discover gating
│ ├── integrity-guard.ts # on_input pattern matching
│ ├── progress-tracker.ts # on_session_end burnout nudges
│ ├── input-revamp.ts # session_start custom input bar
│ └── lib/
│ ├── config.ts # Config loader (deepMerge, search paths)
│ └── ui.ts # Shared UI primitives (row, sep, skillsList)
├── skills/
│ └── generic-attempt/
│ ├── SKILL.md # Evaluation mode prompt
│ └── rubric.json # Built-in 5-criterion rubric
└── themes/
└── pisces-editorial-noir.json
License
MIT