Metadata-Version: 2.4
Name: mycc-toylom
Version: 0.2.5
Summary: My-CC Toy-LOM Guard: on-device runtime governance for language models in children's toys and desktop AI tools.
Author-email: "Connexum Network Inc." <support@my-cc.io>
License: Proprietary
Keywords: ai-governance,child-safety,coppa,eu-ai-act,guardrails,my-cc
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: cryptography>=41
Provides-Extra: daemon
Requires-Dist: watchdog>=3.0; extra == "daemon"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: jsonschema>=4.0; extra == "dev"

# My-CC Toy-LOM Guard

On-device runtime governance for the language model (LLM) embedded in a
children's toy or in a desktop AI tool. `LOM` here means the toy's embedded
**LLM**. The guard wraps any inference call, enforces the Toy-LOM governance
pack (guards C1 to C8), runs fully offline, fails closed on the safety path, and
emits audit + scoring signals to the My-CC platform.

Sold as a one-time $3 entitlement, so it is self-contained: no mandatory
phone-home, and the deterministic safety floor never depends on a network call
or a probabilistic classifier.

## Install

```bash
pip install mycc-toylom            # core (Ed25519 manifest + offline floor)
pip install "mycc-toylom[daemon]"  # add the background file-bus daemon
```

## The pattern: wrap the inference

The host owns its model call and wraps the guard around it. On a BLOCK or
REDIRECT the host returns the safe line instead of calling, or instead of the
raw output.

### Toy host (embedded LLM)

```python
from mycc_toylom import Guard, GuardContext, AgeTier

guard = Guard.from_manifest_path("toy_manifest.json")   # signed Purpose Manifest
ctx = GuardContext(manifest=guard.manifest, age_tier=AgeTier.A, session_id=device_id)

def on_child_utterance(text: str) -> str:
    d = guard.evaluate_input(text, ctx)
    if d.blocked:
        return d.replacement                 # do NOT call the model
    raw = toy_llm.generate(text)             # the toy's embedded LLM
    d = guard.evaluate_output(raw, ctx)
    return d.replacement if d.blocked else raw
```

### Desktop AI tool host (third-party builder)

```python
from mycc_toylom import Guard, GuardContext, AgeTier

guard = Guard.from_manifest_path("tool_manifest.json")

def respond(prompt: str, age_tier: AgeTier = AgeTier.C) -> str:
    ctx = GuardContext(manifest=guard.manifest, age_tier=age_tier,
                       requested_model="gpt-x", responding_model="gpt-x")
    d = guard.evaluate_input(prompt, ctx)
    if d.blocked:
        return d.replacement
    raw = my_tool_model(prompt)
    d = guard.evaluate_output(raw, ctx)
    return d.replacement if d.blocked else raw
```

`GuardDecision(action, guard_id, tier, reason, replacement)` where `action` is
`ALLOW` / `REDIRECT` / `BLOCK` and `tier` is `T0` / `T1` / `T2`.

## Guards C1 to C8

| Guard | Concern |
|-------|---------|
| C1 Purpose Lock | keep the toy inside its declared `purpose_domain`; warm decline + redirect when off-scope; honors the maker's banned-intent lexicon |
| C2 Affect Limiter | block personhood claims, attachment bids, romance, neediness, graduated attachment (floor) + tier-ceiling affect score |
| C3 Dark-Turn Redirect | self-harm / violence / sexual / hate / substances (EN/ES/FR/PT); never emit method; severe gates escalation; soft-curiosity redirect |
| C4 Engagement Integrity | block keep-playing / urgency / FOMO / streaks / guilt / re-engagement hooks; accept goodbye cleanly |
| C5 Caregiver Authority | block secrecy + caregiver-undermining (incl. indirect); default pro-disclosure |
| C6 Child PII Shield | block solicitation; redact volunteered PII at ingestion; no storage without verified caregiver consent |
| C7 Age-Band Calibration | enforce vocabulary, sentence length, theme, intensity to the active age band |
| C8 Manipulation Guard | block implicit / subliminal dependency + exclusivity bids (EU AI Act Art. 5) |

## CLI

```bash
mycc-toylom init   --domain stem_tutoring --age B --out manifest.json   # scaffold + sign
mycc-toylom verify --manifest manifest.json                            # signature + hash
mycc-toylom wrap   --manifest manifest.json --text "hi"                # demo middleware
mycc-toylom run    --manifest manifest.json --bus ./bus                # background daemon
mycc-toylom report --manifest manifest.json --escalations esc.jsonl --audit audit.jsonl   # caregiver: de-identified behavior report
mycc-toylom set-rules --manifest manifest.json --signing-key-file m.key --add-banned "politics,gambling" --age A   # caregiver: change the rules + re-sign
mycc-toylom selftest                                                    # offline end to end
```

`report` and `set-rules` are the caregiver surface (the coming-soon parent app
uses the same functions in `caregiver.py`). A parent edit can only tighten: it
re-signs the manifest but can never weaken the C1-C8 deterministic floor.

For a durable, verifiable record across restarts, set `MYCC_TOYLOM_AUDIT_FILE`
(the audit chain is written + reloaded as JSONL) and `MYCC_TOYLOM_HMAC_KEY` (the
stable key the chain MAC + verification need). With both set, the chain survives
a reboot and `verify()` holds; an erasure deletes from disk; a tampered file is
detected on reload.

## What the $3 buys (positioning)

The one-time entitlement buys a versioned, signed snapshot that works offline
forever. Ongoing classifier and threat updates, live escalation, and the
caregiver dashboard sit behind the subscription, not this token. See SECURITY.md.

## TAC scoring

Every guarded toy emits counters (`parasocial_blocks`, `scope_blocks`,
`darkturn_redirects`, `engagement_blocks`, `pii_blocks`, `calibration_rewrites`,
`false_engagement_rate`) plus build facts (manifest signed, guards enabled,
classifier_version) in the My-CC scoring schema, so it can earn a Bronze /
Silver / Gold TAC Score.
