{"id":"fe447964-c515-4229-aa1d-00aae47cd33d","entityType":"agent","slug":"clawhub-chrischall-pickuppatrol-mcp","name":"pickuppatrol-mcp","canonicalUrl":"https://www.xpersona.co/agent/clawhub-chrischall-pickuppatrol-mcp","canonicalPath":"/agent/clawhub-chrischall-pickuppatrol-mcp","generatedAt":"2026-10-11T14:16:03.537Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":null},"description":"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times. Skill: pickuppatrol-mcp Owner: chrischall Summary: Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times. Tags: latest:1.2.1 Version history: v1.2.1 | 2026-10-09T23:27:54.931Z | auto - Removed the file: skill-card.md - No changes to core API or functional documentation. - Simplified fil","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:pickuppatrol-mcp","sourceUrl":"https://clawhub.ai/chrischall/pickuppatrol-mcp","homepage":"https://clawhub.ai/chrischall/skills/pickuppatrol-mcp","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/chrischall/pickuppatrol-mcp","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/chrischall/skills/pickuppatrol-mcp","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":61,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day ch"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":null},"stars":null,"forks":null,"downloads":1089,"packageName":null,"latestVersion":"1.2.1","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T10:19:11.930Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T10:19:11.996Z","lastCrawledAt":"2026-10-11T10:19:11.930Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T10:19:11.930Z","lastVerifiedAt":null,"highlights":[{"version":"1.2.1","createdAt":"2026-10-09T23:27:54.931Z","changelog":"- Removed the file: skill-card.md - No changes to core API or functional documentation. - Simplified file structure by eliminating redundant or unnecessary documentation.","fileCount":4,"zipByteSize":6857},{"version":"1.2.0","createdAt":"2026-10-07T13:39:26.121Z","changelog":"- Removed the file: skill-card.md - No user-facing or functional changes to the API or documentation.","fileCount":4,"zipByteSize":6998},{"version":"1.1.4","createdAt":"2026-10-05T02:51:29.405Z","changelog":"- skill-card.md was removed. - No code or functional changes; documentation only. - The core shell usage guide and API documentation remain unchanged.","fileCount":4,"zipByteSize":6955},{"version":"1.1.3","createdAt":"2026-10-03T01:42:52.399Z","changelog":"- Removed the file skill-card.md. - No user-facing functionality or API changes. - Documentation and functionality remain unchanged.","fileCount":4,"zipByteSize":6913},{"version":"1.1.2","createdAt":"2026-09-30T16:58:01.250Z","changelog":"- Removed the file skill-card.md. - No user-facing changes were made to the skill's functionality or documentation.","fileCount":4,"zipByteSize":6952},{"version":"1.1.1","createdAt":"2026-09-25T15:57:05.275Z","changelog":"- Removed the skill-card.md file. - No changes to functionality or documentation aside from this file removal.","fileCount":4,"zipByteSize":6959},{"version":"1.1.0","createdAt":"2026-09-24T15:12:54.725Z","changelog":"- Removed the file: skill-card.md. - No changes to functionality or documentation content. - This is a minor housekeeping update with no user-visible impact.","fileCount":4,"zipByteSize":7191},{"version":"1.0.2","createdAt":"2026-09-23T21:44:23.914Z","changelog":"- Removed the skill-card.md file. - No user-facing or functional changes to the API or documentation. - Release is a minor update focused on project file structure cleanup.","fileCount":4,"zipByteSize":7110}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17cjx1a349nz5apaqp02vgz4h85728z:pickuppatrol-mcp","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T14:16:03.534Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-chrischall-pickuppatrol-mcp/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":null},"readme":"Skill: pickuppatrol-mcp\n\nOwner: chrischall\n\nSummary: Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\n\nTags: latest:1.2.1\n\nVersion history:\n\nv1.2.1 | 2026-10-09T23:27:54.931Z | auto\n\n- Removed the file: skill-card.md\n- No changes to core API or functional documentation.\n- Simplified file structure by eliminating redundant or unnecessary documentation.\n\nv1.2.0 | 2026-10-07T13:39:26.121Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing or functional changes to the API or documentation.\n\nv1.1.4 | 2026-10-05T02:51:29.405Z | auto\n\n- skill-card.md was removed.\n- No code or functional changes; documentation only.\n- The core shell usage guide and API documentation remain unchanged.\n\nv1.1.3 | 2026-10-03T01:42:52.399Z | auto\n\n- Removed the file skill-card.md. \n- No user-facing functionality or API changes. \n- Documentation and functionality remain unchanged.\n\nv1.1.2 | 2026-09-30T16:58:01.250Z | auto\n\n- Removed the file skill-card.md.\n- No user-facing changes were made to the skill's functionality or documentation.\n\nv1.1.1 | 2026-09-25T15:57:05.275Z | auto\n\n- Removed the skill-card.md file.\n- No changes to functionality or documentation aside from this file removal.\n\nv1.1.0 | 2026-09-24T15:12:54.725Z | auto\n\n- Removed the file: skill-card.md.\n- No changes to functionality or documentation content.\n- This is a minor housekeeping update with no user-visible impact.\n\nv1.0.2 | 2026-09-23T21:44:23.914Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing or functional changes to the API or documentation.\n- Release is a minor update focused on project file structure cleanup.\n\nv1.0.1 | 2026-09-23T15:40:22.880Z | auto\n\n- Removed the file: skill-card.md\n- No other changes to functionality or documentation.\n\nv1.0.0 | 2026-09-20T02:49:30.041Z | auto\n\n- Removed the skill-card.md file.\n- No user-facing feature or behavioral changes.\n\nv0.2.1 | 2026-09-10T17:56:25.816Z | auto\n\n- Removed the file skill-card.md.\n- No other changes made to documentation or core functionality.\n\nv0.2.0 | 2026-09-04T22:24:08.120Z | auto\n\n- Removed the file skill-card.md from the repository.\n- No user-facing changes to commands or documented API usage.\n- No modifications to SKILL.md content or examples.\n\nv0.1.2 | 2026-08-19T02:17:29.779Z | auto\n\n- Removed the file: skill-card.md\n- No user-facing features or documentation were changed.\n- This update is housekeeping only; there are no behavioral or usage changes.\n\nv0.1.1 | 2026-08-16T23:22:24.923Z | auto\n\n- Removed file: skill-card.md\n- No functional changes to code or documentation content.\n- Minor cleanup in project files.\n\nv0.1.0 | 2026-08-16T21:06:41.445Z | auto\n\nInitial release of pickuppatrol-api: interact with PickUp Patrol from the command line.\n\n- Enables reading and updating children’s school dismissal plans using plain curl commands.\n- Supports authentication and session management without a browser.\n- Provides examples for listing students, reading defaults, and viewing per-day overrides.\n- Documents requirements for plan changes and how to verify updates.\n- Warns about lockout risk on failed logins; always validate credentials before retrying.\n\nArchive index:\n\nArchive v1.2.1: 4 files, 6857 bytes\n\nFiles: references/api.md (6766b), skill-card.md (1755b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.2.1:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.2.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.2.1\",\n  \"publishedAt\": 1791588474931\n}\n\nFile v1.2.1:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.2.1:skill-card.md\n\n## Description:\n\nProvides shell guidance for reading and changing children's school dismissal plans on PickUp Patrol, including weekly defaults, date-specific changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or guardians with a PickUp Patrol account can use this guide to inspect school dismissal options and student plans, then prepare and verify changes from a shell.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Exposing account credentials, session cookies, or student data stored in temporary files.\n\nMitigation: Use your own account; protect and delete temporary authentication, cookie, and student files after use.\n\nRisk: Incorrect write commands can change live student dismissal plans or overwrite student fields.\n\nMitigation: Review every PUT/PATCH command before running it, back up full student JSON before whole-record updates, and re-read plans to verify changes.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance for authenticated reads, plan updates, and verification of changes.]\n\n## Skill Version(s):\n\n1.2.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.2.0: 4 files, 6998 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2062b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.2.0:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.2.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.2.0\",\n  \"publishedAt\": 1791380366121\n}\n\nFile v1.2.0:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.2.0:skill-card.md\n\n## Description:\n\nRead and change children's school dismissal plans on PickUp Patrol from a shell using curl.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents and authorized caregivers can inspect student dismissal options and weekly defaults, then prepare and verify date-specific or recurring plan changes from a shell.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Incorrect dismissal changes can affect how a child leaves school, and changes after the cutoff may be silently ignored.\n\nMitigation: Review each update against the school's transportation rules and cutoff, then re-read the plan to verify its transportation and note.\n\nRisk: Credentials, session cookies, and student records are sensitive; fixed temporary files may expose them.\n\nMitigation: Keep secrets out of command lines, use a private temporary directory with restrictive permissions, and remove temporary files after use.\n\nRisk: Whole-record updates to weekly defaults can overwrite student data; repeated rejected logins can lock the account.\n\nMitigation: Back up student JSON before updating the complete record, review PUT commands, and stop after a failed login to correct credentials.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with bash code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands use curl and jq to read or update dismissal plans.]\n\n## Skill Version(s):\n\n1.2.0 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.4: 4 files, 6955 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2018b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.1.4:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.1.4:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.1.4\",\n  \"publishedAt\": 1791168689405\n}\n\nFile v1.1.4:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.1.4:skill-card.md\n\n## Description:\n\nProvides shell guidance for reading and changing children's PickUp Patrol dismissal plans, including weekly defaults, date-specific plans, and school cutoffs.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or authorized caregivers can use the skill to inspect their children's school dismissal plans and prepare changes to daily or weekly transportation arrangements through their own PickUp Patrol account.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: An incorrect write could change a child's real dismissal arrangements.\n\nMitigation: Require human review of the child, date, transportation option, note, and school cutoff before each write; avoid unattended automation.\n\nRisk: Account credentials, session cookies, or authentication responses could be exposed.\n\nMitigation: Keep passwords, cookies, authentication responses, and temporary files private.\n\nRisk: A change may be silently ignored after a school cutoff despite a successful-looking response.\n\nMitigation: Re-read the plan and verify both the transportation option and note after writing.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [ClawHub skill release](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands may read or change live account data when executed with an authenticated session.]\n\n## Skill Version(s):\n\n1.1.4 (source: server-resolved ClawHub release)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.3: 4 files, 6913 bytes\n\nFiles: references/api.md (6766b), skill-card.md (1913b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.1.3:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.1.3:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.1.3\",\n  \"publishedAt\": 1790991772399\n}\n\nFile v1.1.3:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.1.3:skill-card.md\n\n## Description:\n\nHelps authorized parents and guardians read and change children's school dismissal plans on PickUp Patrol using shell commands.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or guardians with authorized PickUp Patrol accounts can check students' dismissal arrangements and update one-day plans or weekly defaults, subject to school rules and cutoffs.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: An unauthorized or mistaken change could affect a child's dismissal arrangements.\n\nMitigation: Require explicit parent or guardian authorization, replace example student details with verified values, and confirm the intended plan before changing it.\n\nRisk: Account credentials, session cookies, and dismissal records are sensitive.\n\nMitigation: Protect authentication files and captured responses like passwords; do not commit or share them.\n\nRisk: A school may silently ignore changes submitted after its cutoff time.\n\nMitigation: Check school rules and re-read the dismissal plan and note after each change to verify the result.\n\n## Reference(s):\n\n- [PickUp Patrol skill listing](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n- [PickUp Patrol API reference](artifact/references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with bash and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [None]\n\n## Skill Version(s):\n\n1.1.3 (source: ClawHub release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.2: 4 files, 6952 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2004b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.1.2:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.1.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.1.2\",\n  \"publishedAt\": 1790787481250\n}\n\nFile v1.1.2:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.1.2:skill-card.md\n\n## Description:\n\nRead and change your children's school dismissal plans on PickUp Patrol from a shell, including student records, weekly defaults, date-specific changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or guardians with an authorized PickUp Patrol account can check their children's dismissal plans and update date-specific or weekly plans using shell commands.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Unauthorized or mistaken changes could affect how a child leaves school.\n\nMitigation: Use only with your own authorized account; confirm the intended student, date, and transportation choice before any write request.\n\nRisk: Passwords, session cookies, tokens, and temporary response files contain sensitive information.\n\nMitigation: Keep credentials and session artifacts private, and delete temporary session files after use.\n\nRisk: A successful response may not mean a plan change was applied, especially after a school cutoff.\n\nMitigation: Require deliberate confirmation before writes, then re-read the plan and verify the transportation and note.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [PickUp Patrol skill release](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with bash code blocks]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands may read or modify live school dismissal plans.]\n\n## Skill Version(s):\n\n1.1.2 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.1: 4 files, 6959 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2040b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.1.1:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.1.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.1.1\",\n  \"publishedAt\": 1790351825275\n}\n\nFile v1.1.1:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.1.1:skill-card.md\n\n## Description:\n\nGuides agents in reading and changing children's school dismissal plans in PickUp Patrol using shell commands.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or authorized caregivers use this skill to inspect students, school dismissal options, weekly defaults, and date-specific plans, then make and verify requested changes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Incorrect student, date, transportation option, or note may change how a child leaves school.\n\nMitigation: Confirm identifiers, dates, and option requirements before writes; re-read the plan and note afterward to verify the requested change.\n\nRisk: Authentication cookies and temporary login files may expose account access if retained or shared.\n\nMitigation: Keep credentials out of command lines and logs, protect temporary authentication files, and remove them when finished.\n\nRisk: A write may appear successful despite being ignored after a school cutoff.\n\nMitigation: Re-read the date-specific plan after writing and compare the transportation option and note, rather than relying on the response status alone.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [pickuppatrol-mcp ClawHub release](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes instructions to check requested changes against subsequent reads.]\n\n## Skill Version(s):\n\n1.1.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.1.0: 4 files, 7191 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2535b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.1.0:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.1.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.1.0\",\n  \"publishedAt\": 1790262774725\n}\n\nFile v1.1.0:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.1.0:skill-card.md\n\n## Description:\n\nRead and change children's school dismissal plans on PickUp Patrol from a shell with curl, including students, weekly defaults, day-by-day changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or authorized guardians use this skill to inspect PickUp Patrol account data and prepare shell commands for changing school dismissal plans. It is most useful when an agent needs to guide API reads, date-specific plan changes, weekly default updates, and post-write verification.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The workflow can change how a child leaves school.\n\nMitigation: Use only an account you are authorized to manage, replace all example student IDs and notes with verified values, and re-read the relevant plan fields before and after every write.\n\nRisk: Live-session-derived examples may contain sensitive child-dismissal context.\n\nMitigation: Replace examples with synthetic or user-verified values before use and avoid sharing generated commands or responses that include student, school, or dismissal details.\n\nRisk: Session cookies and authentication responses may be written to temporary locations during shell use.\n\nMitigation: Keep session files out of shared temp locations, limit their lifetime, and remove cookie jars or auth response files after the task is complete.\n\nRisk: Repeated failed login attempts can trigger account lockout.\n\nMitigation: Stop after one rejected login attempt and correct credentials or account state before retrying.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline bash and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance may include authenticated API calls that require user-provided PickUp Patrol credentials and careful verification after writes.]\n\n## Skill Version(s):\n\n1.1.0 (source: ClawHub release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.2: 4 files, 7110 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2394b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.0.2:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.0.2\",\n  \"publishedAt\": 1790199863914\n}\n\nFile v1.0.2:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.0.2:skill-card.md\n\n## Description:\n\nRead and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl, including students, weekly defaults, day-by-day changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and technically comfortable parents can use this skill to script authorized PickUp Patrol reads and updates from a shell. It helps inspect student dismissal data, transport options, daily overrides, weekly defaults, and cutoff-related verification steps.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Examples include live-looking student, school, transportation, date, note, and car-number details.\n\nMitigation: Replace all realistic identifiers and dismissal details with clearly synthetic examples before sharing or installing.\n\nRisk: The skill handles PickUp Patrol passwords and session cookies.\n\nMitigation: Use only authorized accounts, keep passwords out of command history, protect the cookie jar, and remove temporary authentication files after use.\n\nRisk: PUT, PATCH, and password-change examples can change real dismissal plans or account state.\n\nMitigation: Treat write commands as production changes, review inputs before execution, and re-read the affected plan or account data to verify the result.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [PickUp Patrol API endpoint](https://app.pickuppatrol.net/api/json/reply)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with curl and jq shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Includes authenticated API read/write examples; PUT, PATCH, and password-change commands can affect real PickUp Patrol accounts and dismissal plans.]\n\n## Skill Version(s):\n\n1.0.2 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.1: 4 files, 7093 bytes\n\nFiles: references/api.md (6766b), skill-card.md (2330b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.0.1:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.0.1:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.0.1\",\n  \"publishedAt\": 1790178022880\n}\n\nFile v1.0.1:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.0.1:skill-card.md\n\n## Description:\n\nRead and change children's school dismissal plans on PickUp Patrol from a shell with curl, including students, weekly defaults, day-by-day changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or authorized guardians can use this skill to inspect PickUp Patrol students, school transportation options, weekly defaults, and specific-day dismissal plans. Agents can also prepare shell commands for account-authorized plan changes when the user intends to make them.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: The skill handles account credentials, session cookies, temporary authentication files, and student dismissal records.\n\nMitigation: Keep passwords out of command history, protect the cookie jar and /tmp authentication files, avoid sharing copied student data, and clean temporary files after use.\n\nRisk: PUT and PATCH examples can change real school dismissal arrangements.\n\nMitigation: Confirm the student, date, school, transportation option, and note before executing write commands, then re-read the plan to verify the result.\n\nRisk: Repeated failed PickUp Patrol logins may count against the account and require support to clear a lockout.\n\nMitigation: Stop after one failed login attempt and correct credentials or contact support instead of retrying automatically.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline bash and JSON command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include curl and jq commands that require account credentials and authenticated PickUp Patrol session cookies.]\n\n## Skill Version(s):\n\n1.0.1 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.0: 4 files, 6987 bytes\n\nFiles: references/api.md (6766b), skill-card.md (1998b), SKILL.md (4916b), _meta.json (135b)\n\nFile v1.0.0:SKILL.md\n\n---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days\n```\n\n## Writes\n\nWrites change how a child actually leaves school. Read\n`GetTransportations` first and obey the option's rules, or the request is\nrejected (or worse, silently ignored):\n\n- `IsNoteRequired` → `Note` must be non-empty\n- `UseCarNumbers` → send `CarNumber`; otherwise omit the key\n- `IsEarlyDismissal` → send `EarlyDismissalTime` as `HH:MM:SS`; otherwise omit it\n- `IsLimited` → only usable if the id is in the student's `LimitedIds`\n\n**Change specific dates** — `Plans` is an array, one entry per date:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'\n```\n\n**Clear a date back to the weekly default** — a null transportation:\n\n```bash\npup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'\n```\n\n**Change the weekly defaults** — there is no default-plans endpoint. Read the\nwhole student, edit `DefaultPlans`, PUT the whole record back\n(`references/api.md` has the read-modify-write recipe).\n\n### Always re-read to verify\n\nA 2xx is not proof. The school silently ignores a change past its cutoff time.\n\n```bash\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '.TransportationId'\n```\n\nCompare `TransportationId` **and `Note`** — never `ModifiedDate`, which advances\non its own and would make every write look successful. The note matters: every\noption seen so far is `IsNoteRequired`, so a note-only edit is ordinary, and an\nid-only comparison would pass without observing it. After *clearing* a date,\nexpect `null` — not the weekday default.\n\nFile v1.0.0:_meta.json\n\n{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.0.0\",\n  \"publishedAt\": 1789872570041\n}\n\nFile v1.0.0:references/api.md\n\n# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId TransportationId Note IsLocked\nTransportationName SchoolName BusRouteUrl ValidationErrors EarlyDismissalTime\nCarNumber LimitedIds IsNotePrivate\n```\n\nReturns the date's **override**, not the effective plan: a date with no specific\nplan reads back `TransportationId: null` even when the student has a weekly\ndefault for that weekday. Merge with `GetStudent(...).DefaultPlans` yourself to\nknow what actually happens on a date.\n\n## Write DTOs\n\n| DTO | Verb | Body |\n|---|---|---|\n| `UpdatePlans` | PUT | `{Plans:[…]}` |\n| `Student` | PUT | the whole student record |\n| `SetDefaultsReviewed` | PUT | `{StudentId, Reviewed}` |\n| `UpdateMiddayPlanCheck` | PUT | `{StudentId, PlanDate, TypeId, Action}` |\n| `MiddayPlan` | PUT | full midday-plan record |\n| `UpdateSendPlanConfirmationEmail` | PUT | `{Send}` |\n| `UpdateUserLanguage` | PATCH | `{Language}` |\n| `AcceptTerms` | PUT | — |\n| `ChangePassword` | PUT | `{CurrentPassword, NewPassword, ConfirmPassword}` |\n\n### UpdatePlans element\n\n```json\n{\"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\",\n \"EarlyDismissalTime\":\"13:00:00\",\"CarNumber\":\"12\"}\n```\n\nOmit `EarlyDismissalTime` unless the option has `IsEarlyDismissal`, and\n`CarNumber` unless it has `UseCarNumbers` — the web app leaves both keys off\notherwise.\n\nBuild several dates at once:\n\n```bash\njq -nc --argjson dates '[\"2026-08-17\",\"2026-08-18\"]' '\n  {Plans: ($dates | map({\n    StudentId:1050046, SchoolId:1703, PlanDate:.,\n    TransportationId:41246, TransportationName:\"PickUp\", Note:\"Chris Hall\"}))}' \\\n| xargs -0 -I{} sh -c 'pup PUT UpdatePlans -d \"$1\"' _ {}\n```\n\n### Weekly defaults: read-modify-write the whole student\n\nThere is no default-plans endpoint. Read the student, replace only\n`DefaultPlans`, PUT the whole record to the `Student` DTO.\n\n```bash\nSTUDENT=1050046\npup GET \"GetStudent?StudentId=$STUDENT\" > /tmp/pup_student.json\n\n# Set Monday (DayId 2) and Tuesday (3) to Bus (41245).\njq '.DefaultPlans = (\n      (.DefaultPlans // []) as $p\n      | [2,3] as $days\n      | ($p | map(select(.DayId as $d | $days | index($d) | not)))\n        + ($days | map({DayId:., TransportationId:41245, TransportationName:\"Bus\", Note:null}))\n      | sort_by(.DayId))' /tmp/pup_student.json > /tmp/pup_student_new.json\n\npup PUT Student -d @/tmp/pup_student_new.json\n\n# Verify: compare TransportationId per DayId, never DefaultsModifiedDate.\npup GET \"GetStudent?StudentId=$STUDENT\" \\\n  | jq '.DefaultPlans | sort_by(.DayId) | map({DayId, TransportationId})'\n```\n\nClear every default with `jq '.DefaultPlans = []'`.\n\nSend every other field back verbatim — the whole record round-trips, so a\ndropped field is a field cleared.\n\n## Gates\n\n- `GetSchoolSettings(...).General.AllowDefaultPlans` — school allows default plans\n- `Student.AllowPlans` — this student's plans may be changed\n- `GetSchoolNotifyTimes` — a weekday with no `NotifyTime<Day>` is not a school day\n- `GetPlanEdit(...).IsLocked` — the cutoff for that date has passed\n\n## Verifying a write\n\nRe-read and compare the fields that prove the change — the transportation id\n**and the note**. Every option seen so far is `IsNoteRequired`, so a note-only\nedit is an ordinary change and an id-only comparison would pass without ever\nobserving it.\n\n- one-off plan → `GetPlanEdit(PlanDate, StudentId)` → `.TransportationId`, `.Note`\n- weekly defaults → `GetStudent(StudentId).DefaultPlans[]` → `.TransportationId`, `.Note`\n\nAfter *clearing* a date, expect `TransportationId: null` — not the weekday\ndefault, which `GetPlanEdit` does not merge in.\n\nExclude `ModifiedDate` and `DefaultsModifiedDate`: they advance on their own, so\nincluding them makes every write look successful.\n\nFile v1.0.0:skill-card.md\n\n## Description:\n\nRead and change children's school dismissal plans on PickUp Patrol from a shell with curl, including students, weekly defaults, day-by-day changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, operators, and parents with authorized PickUp Patrol accounts use this skill to script reads and carefully verified updates to student dismissal plans.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Commands can change live child dismissal plans.\n\nMitigation: Use only accounts you control, replace all example IDs and dates, inspect each write payload, and re-read PickUp Patrol fields after every update.\n\nRisk: Session cookies and authentication artifacts may remain in local temporary files.\n\nMitigation: Avoid shared machines and delete /tmp/pup_* files and cookie jars after use.\n\nRisk: Repeated rejected logins can count against the account and may trigger lockout.\n\nMitigation: Stop after one failed login attempt and correct credentials before trying again.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n- [ClawHub skill page](https://clawhub.ai/chrischall/skills/pickuppatrol-mcp)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown with inline bash, curl, jq, and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Commands can read account data and write live dismissal plans; verify changes with follow-up reads.]\n\n## Skill Version(s):\n\n1.0.0 (source: release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.","readmeExcerpt":"Skill: pickuppatrol-mcp Owner: chrischall Summary: Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times. Tags: latest:1.2.1 Version history: v1.2.1 | 2026-10-09T23:27:54.931Z | auto - Removed the file: skill-card.md - No changes to core API or functional documentation. - Simplified fil","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\"},{"language":"bash","snippet":"curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\""},{"language":"bash","snippet":"export PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}"},{"language":"bash","snippet":"pup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?PlanDate=2026-08-17&StudentId=1050046\" | jq '{TransportationName,Note,IsLocked}'\npup GET \"GetInvalidPlanDates?SchoolId=1703\" | jq 'length'   # non-school days"},{"language":"bash","snippet":"pup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":41246,\"TransportationName\":\"PickUp\",\"Note\":\"Chris Hall\"}]}'"},{"language":"bash","snippet":"pup PUT UpdatePlans -d '{\"Plans\":[{\n  \"StudentId\":1050046,\"SchoolId\":1703,\"PlanDate\":\"2026-08-17\",\n  \"TransportationId\":null,\"TransportationName\":\"Default plan\",\"Note\":null}]}'"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: pickuppatrol-api\ndescription: \"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times.\"\n---\n\n# PickUp Patrol from a shell\n\n`app.pickuppatrol.net` is a ServiceStack JSON API behind an Ionic/Vue SPA. It is\nreachable **server-side with plain `curl`** — no bot wall, no captcha, no\nbrowser bridge. Use this when you want PickUp Patrol data in a script or on a\nmachine without the `pickuppatrol-mcp` server.\n\nFull captured shapes: `references/api.md`.\n\n## Sign in once per shell\n\n```bash\nexport PUP_USER='you@example.com'\nread -rs PUP_PASS && export PUP_PASS      # never put the password in a command line\nexport PUP=https://app.pickuppatrol.net/api/json/reply\n\npup_login() {\n  local jar; jar=$(mktemp -t pupjar)\n  curl -sS -c \"$jar\" -X POST \"$PUP/Authenticate\" \\\n    -H 'Content-Type: application/json' \\\n    -d \"$(jq -nc --arg u \"$PUP_USER\" --arg p \"$PUP_PASS\" \\\n          '{provider:\"credentials\",UserName:$u,Password:$p,RememberMe:true}')\" \\\n    -o /tmp/pup_auth.json -w '%{http_code}' >/tmp/pup_code\n  [ \"$(cat /tmp/pup_code)\" = 200 ] || { jq -r '.ResponseStatus.Message' /tmp/pup_auth.json >&2; return 1; }\n  export PUP_JAR=\"$jar\"\n  # This deployment returns cookies only — BearerToken comes back null. The\n  # JWT path exists server-side, so keep a token if one ever appears.\n  PUP_TOKEN=$(jq -r '.BearerToken // empty' /tmp/pup_auth.json); export PUP_TOKEN\n}\n\n# Every call goes through this: it sends the session cookies, and the bearer\n# token as well when the deployment issued one.\npup() {\n  local method=$1 dto=$2; shift 2\n  local -a auth=(-b \"$PUP_JAR\")\n  [ -n \"$PUP_TOKEN\" ] && auth+=(-H \"Authorization: Bearer $PUP_TOKEN\")\n  curl -sS -X \"$method\" \"$PUP/$dto\" -H 'Content-Type: application/json' \"${auth[@]}\" \"$@\"\n}\n```\n\n**Never re-run a rejected login.** PickUp Patrol answers bad credentials with\n`ResponseStatus.ErrorCode` starting `LOGIN-ERROR`, counts the attempt against\nthe account, and a lockout clears only through their support desk. One failure\n= stop and fix the credentials.\n\n## Reads\n\n```bash\npup GET GetSession | jq '{name:.DisplayName, email:.Email, kids:[.Children[].StudentId]}'\npup GET GetChildren | jq -r '.[] | \"\\(.StudentId)  \\(.FirstName) — \\(.SchoolName)\"'\n\n# Weekly default plan for one student. DayId is 1-based, SUNDAY = 1.\npup GET GetChildren | jq '.[] | select(.StudentId==1050046) | .DefaultPlans\n  | sort_by(.DayId) | map({day:.WeekDayName, option:.TransportationName, note:.Note})'\n\n# The dismissal options a school offers, with the rules each imposes.\npup GET \"GetTransportations?SchoolId=1703\" | jq -r '.[] | select(.IsActive)\n  | \"\\(.TransportationId)\\t\\(.Name)\\tnote=\\(.IsNoteRequired)\\tcar=\\(.UseCarNumbers)\\tearly=\\(.IsEarlyDismissal)\"'\n\n# GetPlanEdit returns the date's OVERRIDE, not the effective plan: a date with\n# no specific plan reads back null even when a weekday default exists.\npup GET \"GetPlanEdit?P"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn700jq4sjtf2anb0rk3ft4p7n856872\",\n  \"slug\": \"pickuppatrol-mcp\",\n  \"version\": \"1.2.1\",\n  \"publishedAt\": 1791588474931\n}"},{"path":"references/api.md","content":"# PickUp Patrol API reference\n\nEvery shape here was read off the shipped SPA's own request DTO classes or\nobserved on a live signed-in session (2026-08-16). No credential, cookie or\ntoken value is recorded.\n\n- Base: `https://app.pickuppatrol.net/api/json/reply/<DtoName>`\n- GET args on the query string; POST/PUT/PATCH args in a JSON body\n- Auth: session cookies from `Authenticate` (`ss-id`, `ss-pid`, `ss-opt`). This\n  deployment returns `BearerToken: null`; send `Authorization: Bearer …` too if\n  one ever appears\n- Errors: ServiceStack `{\"ResponseStatus\":{\"ErrorCode\",\"Message\",\"Errors\":[…]}}`;\n  an unauthenticated call to any authorised DTO is a bare `401`\n\nAssumes the `pup` / `pup_login` shell functions from `SKILL.md`.\n\n## Authentication\n\n```bash\ncurl -sS -c jar -X POST \"$PUP/Authenticate\" -H 'Content-Type: application/json' \\\n  -d '{\"provider\":\"credentials\",\"UserName\":\"…\",\"Password\":\"…\",\"RememberMe\":true}'\n```\n\nResponse: `{UserId, SessionId, UserName, DisplayName, BearerToken, RefreshToken,\nRoles, Permissions, ResponseStatus}` — `BearerToken` and `RefreshToken` come\nback null here; the session is the cookies.\n\nTwo-factor accounts (`User.OtpTypeId` set) need `POST /CreateOtp {OtpTypeId}`\nthen `PUT /VerifyOtp {Otp, RememberMe}`. Token refresh is\n`POST /GetAccessToken {refreshToken}` or `GET /RequestNewtoken?OldToken=…`.\n\n## Read DTOs\n\n| DTO | Args |\n|---|---|\n| `GetSession` | — |\n| `GetSessionInfo` | — |\n| `GetChildren` | — |\n| `GetStudent` | `StudentId`, `MergeTimeWithNote?` |\n| `GetDefaultPlansReviewNeeded` | — |\n| `GetParentPlans` | `StartDate`, `EndDate` |\n| `GetPlanEdit` | `PlanDate`, `StudentId` |\n| `GetBoldedDates` | `StartDate`, `EndDate` (dates differing from the default) |\n| `GetInvalidPlanDates` | `SchoolId` (non-school days) |\n| `GetTransportations` | `SchoolId` |\n| `GetCarNumbers` | `SchoolId` |\n| `GetSchool` | `SchoolId` |\n| `GetSchoolNotifyTimes` | `SchoolId` |\n| `GetSchoolSettings` | `SchoolId` |\n| `GetMiddayPlan` | `StudentId`, `PlanDate`, `TypeId?` |\n| `GetParentHealthScreenAudits` | `ScreenDate` |\n| `GetTermsOfUse` | — |\n\n### Student\n\n```\nStudentId SchoolId SchoolName FirstName LastName IsActive SASId TeacherId\nAllowPlans CreateDate CreatedBy ModifiedDate ModifiedBy DefaultsModifiedDate\nDefaultPlanModifiedBy DefaultsReviewedDate DefaultsReviewedBy DefaultPlans\nSafetyFlag DefaultCarNumber LimitedIds\n```\n\n`DefaultPlans[]`:\n\n```json\n{\"StudentId\":1050046,\"DayId\":2,\"TransportationId\":41246,\"Note\":\"Chris Hall\",\n \"TransportationName\":\"PickUp\",\"WeekDayName\":\"Monday\",\"EarlyDismissalTime\":null,\n \"CarNumber\":null,\"UseCarNumbers\":false}\n```\n\n`DayId` is 1-based with **Sunday = 1** — verified from a live record where\n`DayId: 2` carried `WeekDayName: \"Monday\"`.\n\n### Transportation\n\n```\nTransportationId SchoolId Name NoteHint IsNoteRequired UseCarNumbers\nIsNotePrivate IsActive Sequence IsEarlyDismissal IsLimited CutoffTime\nCutoffTime{Sunday…Saturday} AllowParentCheck\n```\n\n### GetPlanEdit\n\n```\nPlanDate StudentId FirstName LastName SchoolId Tran"},{"path":"skill-card.md","content":"## Description:\n\nProvides shell guidance for reading and changing children's school dismissal plans on PickUp Patrol, including weekly defaults, date-specific changes, and school cutoff times.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[chrischall](https://clawhub.ai/user/chrischall)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nParents or guardians with a PickUp Patrol account can use this guide to inspect school dismissal options and student plans, then prepare and verify changes from a shell.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Exposing account credentials, session cookies, or student data stored in temporary files.\n\nMitigation: Use your own account; protect and delete temporary authentication, cookie, and student files after use.\n\nRisk: Incorrect write commands can change live student dismissal plans or overwrite student fields.\n\nMitigation: Review every PUT/PATCH command before running it, back up full student JSON before whole-record updates, and re-read plans to verify changes.\n\n## Reference(s):\n\n- [PickUp Patrol API reference](references/api.md)\n\n## Skill Output:\n\n**Output Type(s):** [Shell commands, Guidance]\n\n**Output Format:** [Markdown with shell and JSON examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Guidance for authenticated reads, plan updates, and verification of changes.]\n\n## Skill Version(s):\n\n1.2.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times. Skill: pickuppatrol-mcp Owner: chrischall Summary: Read and change your children's school dismissal plans on PickUp Patrol (app.pickuppatrol.net) from a shell with curl — students, weekly defaults, day-by-day changes, school cutoff times. Tags: latest:1.2.1 Version history: v1.2.1 | 2026-10-09T23:27:54.931Z | auto - Removed the file: skill-card.md - No changes to core API or functional documentation. - Simplified fil","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1001,"uniquenessScore":54,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T10:19:11.996Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:16:03.537Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}