Tools
Plugin German Tutor
German tutoring agent plugin for OpenClaw — CEFR-calibrated, scenario-based lessons with graduated corrections (Sprechi)
Configuration Example
"plugins": {
"entries": {
"german-tutor": {
"enabled": true,
"config": {
"agentId": "sprechi",
"activeProfile": "jae"
}
}
}
}
README
# Sprechi — German Tutoring Agent for OpenClaw
An OpenClaw agent that conducts one-on-one German conversation lessons on
Discord. Sprechi speaks Hochdeutsch only, calibrates to the learner's CEFR
level, runs task-based scenarios, and corrects errors with graduated
reproduction prompts — all grounded in second language acquisition research.
## What this directory contains
```
german-tutor/
├── README.md ← you are here
├── package.json ← npm package manifest
├── openclaw.plugin.json ← OpenClaw plugin registration + config schema
├── index.ts ← plugin entry point (registers the hook)
├── src/ ← plugin source code
│ ├── config.ts ← config parser
│ ├── profile.ts ← learner profile loader
│ ├── scenarios.ts ← scenario loader
│ ├── levels.ts ← CEFR level doc loader
│ └── prompt-inject.ts ← builds the context block
└── content/ ← all teaching content (edit these, not the code)
├── persona.md ← the 11 pedagogical principles
├── levels/ ← CEFR reference docs
│ ├── A1.md
│ ├── A2.md
│ └── B1.md
├── profiles/ ← learner profiles (one per student)
│ └── jae.json
└── scenarios/ ← 13 task-based scenarios
├── biergarten.json
├── bahnhof.json
└── ... (11 more)
```
## How it works
Sprechi is both a configured **agent** in OpenClaw and a **plugin** that
supplements that agent with German tutoring context. The two pieces work
together:
### The agent
- Defined in `openclaw.json` under `agents.list` as `sprechi`
- Has its own workspace at `~/.openclaw/workspace-sprechi/`
- The workspace contains `SOUL.md` — Sprechi's core identity and
teaching philosophy that OpenClaw loads into the system prompt automatically
- Bound to one specific Discord channel via an entry in `bindings` — any
message in that channel routes to `sprechi` instead of the default agent
- Threads inside that channel inherit the binding automatically
### The plugin
- Registered in `openclaw.json` under `plugins.entries.german-tutor`
- On every turn in Sprechi's channel, the plugin's `before_prompt_build`
hook fires and injects a context block in front of the system prompt
- The context block contains:
1. The full 11 pedagogical principles from `content/persona.md`
2. The CEFR reference document matching the learner's level (A1, A2, or B1)
3. A learner-context block summarizing the learner's profile
4. The current scenario (role, information gap, vocabulary, success criteria)
5. A correction-watch list of the learner's top recurring errors, each
tagged with priority and a specific action directive
The plugin guards on `ctx.agentId === "sprechi"` so it only activates for
this agent. Other OpenClaw agents are unaffected.
### Per-turn flow
```
User sends Discord message in bound channel
│
▼
OpenClaw routes to sprechi agent
│
▼
before_prompt_build hook fires
│
▼
Plugin loads profile + level doc + scenario + persona
│
▼
Plugin builds context block (~2500 tokens)
│
▼
Context block prepended to system prompt
│
▼
Agent call made with full context (persona + CEFR + profile + scenario)
│
▼
Response posted to Discord
│
▼
chatlog plugin logs the exchange to markdown
```
## Configuration
### Where things live
| What | Path |
|------|------|
| Main OpenClaw config | `~/.openclaw/openclaw.json` |
| Agent workspace (SOUL.md) | `~/.openclaw/workspace-sprechi/` |
| Plugin code + content | `~/openclaw/extensions/german-tutor/` |
| Extension logs | `~/.openclaw/logs/` and `/tmp/openclaw/openclaw-*.log` |
| Chatlog output | `~/.openclaw/chatlog/` (see chatlog plugin) |
### Plugin config in openclaw.json
```json
"plugins": {
"entries": {
"german-tutor": {
"enabled": true,
"config": {
"agentId": "sprechi",
"activeProfile": "jae"
}
}
}
}
```
- `agentId`: which agent the plugin activates for. Defaults to `sprechi`.
- `activeProfile`: which profile file to load from `content/profiles/`.
Defaults to `jae`. Set to `partner` to load `content/profiles/partner.json`.
### Agent registration
```json
"agents": {
"list": [
{
"id": "sprechi",
"name": "Sprechi",
"workspace": "/home/agentshik/.openclaw/workspace-sprechi"
}
]
}
```
### Channel binding
```json
"bindings": [
{
"agentId": "sprechi",
"match": {
"channel": "discord",
"peer": { "kind": "channel", "id": "1494366718292660224" }
}
}
]
```
Replace the channel ID to bind Sprechi to a different Discord channel.
---
## Common tasks
### Change the learner's current scenario
Edit the profile file and change `current_scenario` to any scenario ID
from `content/scenarios/`:
```bash
nano ~/openclaw/extensions/german-tutor/content/profiles/jae.json
```
```json
{
"current_scenario": "therapie", ← change this
...
}
```
Available scenario IDs: `biergarten`, `bahnhof`, `wohnung`, `arzt`,
`wegbeschreibung`, `cafe`, `reklamation`, `verabredung`, `party`,
`beschwerde`, `storepruefung`, `kita`, `therapie`.
**No restart needed** — the plugin reads the profile on every turn.
### Change the learner's CEFR level
Edit the profile file:
```json
{
"cefr_level": "B1", ← change to A1, A2, or B1
"cefr_by_skill": {
"speaking": "B1",
"listening": "B1",
"reading": "B1",
"writing": "A2"
},
...
}
```
The plugin will automatically load `content/levels/B1.md` instead of A2.
### Update recurring errors
After a tutoring session, update `recurring_errors` in the profile so
Sprechi knows what to watch for:
```json
"recurring_errors": [
{
"pattern": "Drops articles before nouns in casual speech",
"priority": "critical",
"principle": "P4",
"action": "correct EVERY time"
},
{
"pattern": "Your new pattern here",
"priority": "high", ← critical | high | medium | low
"principle": "P5", ← which principle applies
"action": "explicit correction + reproduction"
}
]
```
Priority order: `critical` > `high` > `medium` > `low`. Keep the list
short — 3-5 items max. Too many and Sprechi will over-correct.
### Add a new scenario
Create a new JSON file in `content/scenarios/` following the schema:
```json
{
"id": "my_scenario",
"title": "Der deutsche Titel",
"description": "Short English description of the situation",
"learner_role": "Description in German of who the learner is",
"agent_role": "Description in German of who Sprechi plays",
"information_gap": "What the learner doesn't know that Sprechi does — this is what drives the scenario forward",
"pre_task_vocab": [
"der Artikel (article)",
"das Wort (word)"
],
"success_criteria": [
"Learner does X",
"Learner correctly uses Y"
],
"grammar_opportunities": [
"Pattern: Ich möchte einen...",
"Structure: weil-clause"
]
}
```
**Rules for scenarios**:
- `pre_task_vocab` items must include the article for all nouns — this
reinforces P4 from the data layer
- 8-12 vocabulary items is the sweet spot
- 4-6 success criteria
- 2-4 grammar opportunities
- The `information_gap` is what makes it a *task-based* scenario, not
just free chat — there needs to be something the learner has to
discover or figure out
Once the file exists, set `current_scenario` in the profile to match
the new `id`.
### Add a new learner profile (for a second user)
1. Copy `content/profiles/jae.json` to `content/profiles/partner.json`
2. Edit the new file — change `user_id`, `display_name`, `cefr_level`,
`recurring_errors`, `interests`, etc.
3. Either:
- Change the plugin's `activeProfile` config to `"partner"` to switch
entirely, OR
- (Future: Block 3) Bind the partner's own Discord channel to a second
agent that uses the partner profile
### Edit Sprechi's teaching persona
Two files control Sprechi's persona:
**`~/.openclaw/workspace-sprechi/SOUL.md`** — core identity and teaching
philosophy. Loaded by OpenClaw automatically into the system prompt.
Keep this focused on *who Sprechi is*.
**`content/persona.md`** — the 11 detailed pedagogical principles
(P1-P11). Injected by the plugin every turn. Keep this focused on
*how Sprechi teaches*.
The distinction is roughly:
- SOUL.md = identity, warmth, Discord formatting rules, session structure
- persona.md = the full teaching methodology with numbered principles
If you want Sprechi to behave differently (e.g. more or less strict
about corrections, different session pacing), edit `content/persona.md`.
### Edit CEFR level constraints
`content/levels/A1.md`, `A2.md`, and `B1.md` define what grammar and
vocabulary Sprechi may use at each level. Each doc has four sections:
- **Grammar you may use**: tenses, clause types, cases, verb types
- **Grammar you must avoid in your own output**: explicit no-go list
- **Vocabulary**: word family count, introduction rate
- **Sentence complexity**: max length, clause rules
- **Correction focus at this level**: what to prioritize catching
If Sprechi is using structures that are too complex or too simple,
edit the corresponding level file.
---
## Monitoring & debugging
### Check if the gateway is running
```bash
systemctl --user status openclaw-gateway.service
```
### Watch the logs
```bash
journalctl --user -u openclaw-gateway.service -f
```
### See config health
```bash
cat ~/.openclaw/logs/config-health.json | python3 -m json.tool
```
### See the full per-turn log
```bash
tail -100 /tmp/openclaw/openclaw-$(date +%Y-%m-%d).log
```
### When to restart the gateway
You need to restart after:
- Editing `openclaw.json` (agent, bindings, or plugin config changes)
- Editing any plugin source code (`.ts` files)
- Adding or removing plugin files
You do **NOT** need to restart after:
- Editing profile JSON files
- Ed
... (truncated)
tools
Comments
Sign in to leave a comment