All skills

Agent skill

ClassCharts

Homework, timetable, school letters, behaviour and attendance from a ClassCharts parent account, through a read-only CLI. Built for a family WhatsApp bot.

Use this skill

Install it into a project with the Skills CLI, or read the files below and adapt them to your own agent.

npx skills add shan8851/agent-skills --skill classcharts
View source on GitHub
SKILL.mdView this file on GitHub
---
name: classcharts
description: Answer a parent's questions about their child's school from ClassCharts (used by many UK secondary schools) with the read-only `classcharts` CLI, covering homework, timetable, announcements, behaviour points, detentions and attendance, plus a one-call daily digest. Use when someone asks "what homework is due?", "anything outstanding?", "what's on tomorrow?", "is there school on Monday?", "what's this week look like?", "has the school sent anything?", "any trips or forms?", "how's behaviour been?", "any detentions?", "how's attendance?" or "anything I need to know?", or wants a school summary for a family chat.
---

# ClassCharts

Read-only CLI for a ClassCharts **parent** account: `classcharts <command> [date] [options]`. It can see what a parent sees in the ClassCharts app. It can't tick homework, reply to consent requests or message teachers.

> The canonical copy of this skill lives in the tool's repo ([shan8851/classcharts-agent](https://github.com/shan8851/classcharts-agent), also printed by `classcharts skill`). This copy is for discovery. If they disagree, trust the one that matches the installed version.

## When to use

- Homework (due, outstanding, overdue, details), lessons for a day or week, whether a day is a school day.
- School announcements, trips, letters and consent forms.
- Behaviour points, detentions, attendance.
- An evening or morning "anything I need to know?" summary.

Do not use for:
- anything that writes (ticking homework, giving consent, messaging the school). Say it's read-only and point the parent to the ClassCharts app;
- other school systems (Arbor, Satchel One, Bromcom and so on);
- interpreting a school's behaviour policy or what a code "really" means. Report it as given and suggest asking the school.

## Before the first command

1. **Check it's installed:** `command -v classcharts` (macOS/Linux) or `where classcharts` (Windows).
2. **If it's missing, ask the user before installing.** Offer `npm install -g @shan8851/classcharts-agent`, which needs Node.js 22.18 or later (`node --version`).
3. **Check there's a login:** `classcharts pupils`. Exit code 2 with "No ClassCharts login found" means nobody has signed in yet.
4. **Sign-in is done by a person, once.** Tell them to run `classcharts setup` in a terminal themselves. It prompts for the parent email and password, tests them, and saves them privately on that machine. Don't ask for the password in chat, don't put it in a command, and don't try to run `setup` yourself: it refuses non-interactive input.

## Pick the command

Start with the narrowest command that answers the question. For a general check-in, `digest` is one call that covers everything.

| Question | Command |
|---|---|
| "Anything I need to know?" / daily summary | `digest` (next school day, homework to do including overdue, detentions, behaviour, announcements, attendance) |
| "What's on tomorrow?" / "Is there school Monday?" | `day tomorrow` / `day monday` |
| "What's the next school day?" (evenings, Fridays, holidays) | `day next` (skips weekends and holidays) |
| "What does this week / next week look like?" | `week` / `week next` |
| "What homework is outstanding?" | `homework --todo` |
| "What homework is due this week?" | `week`, or `homework --from today --to friday` |
| "Tell me more about the art homework" | `homework --full` (full text, links, attachment names) |
| "Has the school sent anything?" / "Any trips or forms?" | `announcements` (`--full` for the whole text) |
| "How's behaviour been?" | `behaviour` (last 7 days; `--from` for longer) |
| "Any detentions?" | `detentions` |
| "How's attendance?" | `attendance` (this school year) |
| "Which children are linked?" | `pupils` (also shows which sections the school turns on) |

- Dates: `YYYY-MM-DD`, `today`, `tomorrow`, `yesterday`, `next`, or a weekday (`friday` means the next Friday, today included).
- More than one child linked: every command needs `--pupil <first name or id>` (or `CLASSCHARTS_PUPIL` set). The CLI refuses to guess and lists the linked children. Run once per child when the question covers all of them. Scheduled or unattended agents should use the id.
- Text output is already compact. Add `--json` only when you need to process the result.
- One `week` call beats five `day` calls. The login is cached between calls, but don't hammer the API.

## Reading the output

- **`[todo]` / `[done]` is a tick, not a mark.** It shows whether someone ticked the homework off in ClassCharts. It says nothing about whether it was handed in or how it was graded. Never say "the teacher marked it done".
- **`[todo]` homework due before today is overdue.** Mention it first.
- **`week 1` / `week 2`** is the school's two-week timetable rotation, when the school publishes it.
- **"No lessons (weekend, holiday or INSET day)"** means ClassCharts returned no lessons for that date. In term time that usually means a holiday or INSET (staff training) day. Say "no lessons on ClassCharts", not "the school is closed", unless an announcement says so.
- **`[consent needed]`** on an announcement means the school wants a parent's response in ClassCharts. You can't give it. Tell the parents, with the deadline if the announcement gives one.
- **Behaviour reasons and scores are each school's own** ("Commendation", "C2", "S1"). Report them as given. Don't guess what a code means.
- **A section the school doesn't show** (text says the school doesn't show it; `hiddenBySchool` in JSON) is the school's ClassCharts setting, not an error. Say so once and move on.
- Times are in the school's timezone. Gaps between lessons are breaks or lunch. Rooms and teachers are as the school records them.

## Answering well

1. **Lead with anything that needs action:** overdue or soon-due `[todo]` homework, consent requests, upcoming detentions. Then the rest.
2. **Celebrate positives.** Keep negatives and detentions factual and low-key, with no lecturing and no speculation about why. The parents decide how to handle them. In a group chat that includes the child, be especially careful.
3. **Keep it short for a chat:** a few lines, no tables, no headings. Leave out empty sections ("no detentions") unless the user asked about them.
4. **Don't post attachment links in a chat.** Attachment URLs (`--json`, `attachments[].url`) are signed and expire. Name the attachment and say it's in ClassCharts.
5. **Read-only:** if asked to tick homework, give consent or message a teacher, say you can't and that the parent can do it in the ClassCharts app.

## Errors

| Exit code | Message | What to do |
|---|---|---|
| 2 | "No ClassCharts login found" | Setup hasn't been run. Ask a person to run `classcharts setup` in a terminal. |
| 2 | "Sent the login back to its sign-in page" | Usually too many login attempts: ClassCharts blocks logins for a few minutes. **Wait; don't retry in a loop**. Tell the user to try again in about five minutes. If it keeps happening after a wait, the email or password is probably wrong, so they should re-run `setup`. |
| 2 | "Login failed" / "not understood" | Wrong details, or ClassCharts changed its login. Tell the human; don't work around it. |
| 1 | Bad date, missing `--pupil`, a refused request, or ClassCharts unavailable or sending something unexpected | The message says what went wrong. Fix the input (for example an inverted `--from`/`--to`, or add `--pupil`) and run once more. Otherwise report it. |

**An error never means "nothing due".** After a failed command, don't report an empty day, "no homework" or "no detentions". Say the check failed. Never fill the gap from memory or guesswork: "I couldn't reach ClassCharts" is a fine answer.

## Adapting to your setup

- **Claude Code:** install the skill under `~/.claude/skills/classcharts/`, or let the tool write the canonical copy: `classcharts skill > ~/.claude/skills/classcharts/SKILL.md`.
- **Codex / OpenClaw / a chat bot (WhatsApp, Telegram):** the agent needs a shell on the machine where `classcharts setup` was run, because the login is saved per user on that machine (`~/.config/classcharts-agent/.env`, plain text protected by file permissions, so treat that file like a password). Run setup as the same OS user the bot runs as.
- **Scheduled digest:** a daily `classcharts digest` from cron or your agent's scheduler works well. Once a day is plenty.

## Common failure modes

- Saying a teacher "marked" homework done, or that `[done]` means handed in.
- Calling a no-lessons day a strike, closure or illness without an announcement saying so.
- Retrying a blocked login in a loop instead of waiting.
- Reporting "nothing due" or an empty day after a command failed.
- Asking for the parent's password in chat, or trying to script `setup`.
- Explaining what a behaviour code means, or moralising about a negative point.
- Pasting attachment URLs into a group chat.
- Offering to give consent or tick homework.

## References

- `references/worked-example.md`: an evening digest turned into a family-chat message, annotated.
- `references/edge-cases.md`: not installed, no login, rate-limited, several children, holidays, hidden sections, write requests, a negative behaviour week, a failed check.
references/edge-cases.mdView this file on GitHub
# Edge cases

Short cases for what goes wrong most often. All names and details are fictional.

## 1. Not installed

`command -v classcharts` prints nothing.

Don't install it unprompted. Ask:

> ClassCharts isn't set up on this machine yet. Want me to install it? It's `npm install -g @shan8851/classcharts-agent` and needs Node.js 22.18 or later. After that, you'll need to sign in once yourself.

If `node --version` is older than 22.18, say so. Don't try to work around it.

## 2. Installed, but nobody has signed in

`classcharts pupils` exits with code 2:

```
No ClassCharts login found. A person needs to run `classcharts setup` once (or set CLASSCHARTS_EMAIL and CLASSCHARTS_PASSWORD).
```

Tell the user:

> You need to sign in once. In a terminal on this machine, run `classcharts setup` and enter your ClassCharts parent email and password when it asks. The password stays on this machine. Please don't send it to me here.

If they paste the password into chat anyway, don't use it. Tell them to run `setup` themselves, and suggest changing the password because it's now in the chat history.

## 3. Rate-limited login

Exit code 2:

```
ClassCharts sent the login back to its sign-in page. Usually that's too many attempts (wait a few minutes, don't retry in a loop); otherwise the email or password is wrong.
```

Don't retry straight away and don't loop. Answer:

> ClassCharts is temporarily blocking sign-ins (too many attempts). I'll need to wait a few minutes before trying again.

If it fails the same way after a real wait (five minutes or more), the saved details are probably wrong. Suggest re-running `classcharts setup`.

## 4. More than one child

The question is "what homework is outstanding?" with no name, and two children are linked. Without `--pupil`, the CLI exits with code 1 instead of guessing:

```
More than one child is linked; choose one with --pupil or CLASSCHARTS_PUPIL. Linked: Alex (1234567), Sam (7654321)
```

Run `homework --todo --pupil Alex` and `homework --todo --pupil Sam`, then answer per child with a short line each. If the question names one child, use `--pupil` for that child only. A scheduled digest or unattended bot should use the ids, or set `CLASSCHARTS_PUPIL`, so a renamed or duplicate first name can't break it.

## 5. Holiday or INSET day

"Is there school tomorrow?" `day tomorrow` returns:

```
Monday 2026-11-02
  No lessons (weekend, holiday or INSET day).
```

Answer with what the tool knows:

> ClassCharts shows no lessons tomorrow, so it looks like a holiday or INSET day. The next day with lessons is Tuesday 3 November.

Get the second part from `day next`. Don't say the school is closed for a strike, weather or anything else unless an announcement says so. If the parent is unsure, `announcements` may have the reason.

## 6. The school hides a section

"How's attendance?" returns:

```
Alex's school doesn't show attendance in ClassCharts.
```

(`{"hiddenBySchool": "attendance"}` with `--json`.) This is the school's choice in ClassCharts, not a broken login. Say so in one line and suggest asking the school office. Don't retry.

## 7. A request to write

"Can you tick off the French homework?" or "Give consent for the trip."

> I can only read ClassCharts, not change anything. You can tick it off (or give consent) in the ClassCharts app.

Don't look for a workaround, and don't claim it's done.

## 8. A bad behaviour week

`behaviour` returns:

```
0 positive, 3 negative (C2 Disruption 2, Late to lesson 1)
- Mon 2026-10-26 · C2 Disruption -1 (Maths)
- Tue 2026-10-27 · C2 Disruption -1 (Maths)
- Thu 2026-10-29 · Late to lesson -1 (Science)
```

In a family chat:

> Behaviour this week: 3 negative points (two "C2 Disruption" in Maths, one late to Science). No positives logged this week.

Factual, short, no guess at what "C2" means at this school, no advice and no tone. If there's an upcoming detention, add it with the date and time. The parents decide what to do.

## 9. Overdue items in an ordinary question

"What's due this week?" `week` shows two items due this week, and `[todo]` homework from last week appears in `digest` or `homework --todo`. If you've seen overdue `[todo]` items, mention them first, even though they weren't asked about. They're usually what the parent most needs to know.

## 10. A failed check isn't "nothing due"

"Anything due tomorrow?" `day tomorrow` exits with code 1 and a message about ClassCharts being unavailable.

Don't answer "nothing due" or "no lessons". An error is not an empty result. Say:

> I couldn't check ClassCharts just now (it didn't respond properly). I'll try again later, or you can look in the app.

Try once more later, not in a loop.

## 11. Attachments

`homework --full --json` includes `attachments[].url`. These links are signed and expire. In a chat, name the file and say it's in ClassCharts. Don't paste the URL. If the user is working with you directly and needs the file, fetch it promptly and don't store the link.
references/worked-example.mdView this file on GitHub
# Worked example: an evening digest for a family chat

All names and details are fictional.

## The request

Wednesday, 19:40, in a family group chat:

> Anything I need to know for school?

## 1. Check the tool and the login

`command -v classcharts` finds it. No need to run `pupils` first: if setup hadn't been done, the next command would exit with code 2 and "No ClassCharts login found".

## 2. One call

A general check-in is what `digest` is for. Don't run `day`, `homework`, `announcements` and `behaviour` separately.

```bash
classcharts digest
```

```
Alex · Wednesday 2026-10-28

Next school day · Thursday 2026-10-29 · week 2
  08:30–15:00  Maths, English ×2, French, PE, Science

Homework to do (due by 2026-11-11)
  - [todo] due Tue 2026-10-27 · History: Source analysis worksheet (30 min, Mr B Teacher)
  - [todo] due Thu 2026-10-29 · French: Vocab test prep (20 min, Mme D Teacher)
  - [todo] due Mon 2026-11-02 · Art: Spellings and definitions (15 min, Miss C Teacher)

Detentions
  None.

Behaviour (last 7 days)
  4 positive (Commendation 3, Excellent Effort 1), 1 negative (C1 Low-level disruption 1)

Announcements (last 7 days)
  - Mon 2026-10-26 · Year 8 museum trip, 13 November [consent needed] (Mrs A Office) [1 attachment]
  - Fri 2026-10-23 · Head of School Bulletin (Mrs A Office) [2 attachments]

Attendance (this school year)
  98.6% (since August 98.6%), 1 absence
```

## 3. Read it

- **History is overdue.** It was due Tuesday and is still `[todo]`. That goes first. `[todo]` means nobody has ticked it off in ClassCharts, so it may have been handed in on paper. Say "still showing as not done", not "Alex didn't do it".
- **French is due tomorrow.** That's next.
- **The trip needs consent.** `[consent needed]` means a parent has to respond in ClassCharts. The agent can't. If the deadline matters, `announcements --full` would show the letter's full text and any reply-by date. Here the title is enough to flag it.
- **Behaviour:** four positives are worth a line of credit. One "C1" is reported as given, briefly, with no guess at what C1 means at this school and no comment.
- **Week 2** is the timetable rotation. It's useful context in a reply about tomorrow, not news.
- **Detentions "None"** and a normal attendance figure don't need mentioning unless asked.
- **Attachments:** name them if useful; don't fetch or post the signed links.

## 4. The reply

> Two bits for school:
> • History source-analysis worksheet was due Tuesday and still shows as not done in ClassCharts.
> • French vocab test prep is due tomorrow (Thursday).
> Also: the Year 8 museum trip on 13 Nov needs a parent's consent in the ClassCharts app.
> Good week otherwise: 3 commendations and an excellent-effort point. (One C1 for low-level disruption too.)
> Tomorrow is a normal day, 08:30–15:00, with PE.

Why this shape:
- Actions first, in date order: overdue, then tomorrow, then the consent request.
- The positive is celebrated; the negative is one factual bracket, not a talking-to.
- No table, no headings, no empty sections, no URLs.
- "Shows as not done in ClassCharts" keeps the `[todo]` meaning honest.
- PE is mentioned because a parent might need to pack a kit. That's a small judgement call. Leave it out if it isn't useful for your family.

## What a plain prompt tends to do instead

- Runs four or five separate commands instead of `digest`.
- Says "the teacher hasn't marked History as complete", treating the tick as a grade.
- Offers to "confirm consent for the trip", which the tool can't do.
- Explains what "C1" probably means, or adds advice about the disruption point.
- Lists every section, including "No detentions" and the attendance percentage, in a long formatted block.