Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Toon Laravel Package

helgesverre/toon

TOON is a compact, human-readable data format that cuts token usage when sending structured data to LLMs. This PHP port offers simple encode and decode methods, works on PHP 8.1+, and supports arrays, objects, and primitives.

View on GitHub
Deep Wiki
Context7

Getting Started

TOON is a single-purpose package: it converts PHP arrays into a compact, LLM-friendly text format and back. There is no service provider, no facade alias, no config file to publish before your first call — you install it and use the static Toon class.

composer require helgesverre/toon
use HelgeSverre\Toon\Toon;

$payload = User::query()->get(['id', 'name', 'plan'])->toArray();

$toon = Toon::encode($payload);
$data = Toon::decode($toon); // back to PHP arrays

The first use case to reach for is prompt stuffing: anywhere you currently interpolate json_encode($rows) into a system or user message, swap in Toon::encode($rows) and measure the delta. This is especially relevant in Laravel apps that use openai-php/laravel, laravel/ai, Prism, or raw HTTP calls to Anthropic/OpenAI — the integration point is always the same, a string in the message content.

Where to look first, in order:

  1. The Quick Start and Basic Usage sections of the README — the format is not JSON, and seeing the output shape (indentation, delimiters, how arrays of uniform objects collapse into rows) is more informative than the spec.
  2. The Configuration Options section — this is where delimiter/indentation/formatting behaviour lives. Read it before you build helpers on top, because changing defaults later will invalidate cached encoded strings.
  3. The upstream TOON Specification repo — worth 10 minutes so you can explain the format to the model in your prompt if needed.

A reasonable day-one deliverable: a ToonPromptFormatter service, a php artisan toon:preview {model} command that dumps before/after token estimates, and one A/B test against your current JSON prompts.

Implementation Patterns

Wrap the static calls, don't scatter them. Toon::encode() in twelve controllers becomes unmaintainable. Centralise:

final class LlmPayload
{
    public static function fromCollection(Collection $rows): string
    {
        return Toon::encode($rows->map(fn ($r) => Arr::only($r->toArray(), [
            'id', 'name', 'plan',
        ]))->all());
    }
}

Column projection matters more than the format does — dropping unused keys is usually a bigger token win than the encoding itself.

Use it for context, not for transport. Encode DB results, config dumps, API responses, or tool results you are feeding to a model. Never use TOON as the body of an HTTP request to a third-party API; JSON remains the wire format everywhere except inside the prompt.

Round-trip for structured output. If you ask the model to reply in TOON, you get a compact response you can Toon::decode() into an array and validate with Laravel's validator. This is the highest-leverage pattern for extraction tasks:

$reply = $client->chat(/* ... */);
$rows  = Toon::decode($reply);          // array
Validator::make(['rows' => $rows], [
    'rows' => ['array'],
    'rows.*.id' => ['required', 'integer'],
])->validate();

Pair this with the package's validation helper (see the README's Validating TOON section) to reject malformed output before decode() throws.

Token benchmarking as a habit. Do not assume savings. Measure per payload shape:

$json = json_encode($rows, JSON_THROW_ON_ERROR);
$toon = Toon::encode($rows);
// compare with your tokenizer of choice, log the ratio in a Pest test

Keep a small fixture set of your real payloads and assert the ratio stays favourable — TOON shines on arrays of uniform objects and can lose on deeply nested, irregular structures.

Cache aggressively, key on the config. If you cache encoded prompts (queue jobs, memoised tool output), include a hash of the TOON config in the cache key so config changes don't silently serve stale formatting.

Testing. Add a property test asserting Toon::decode(Toon::encode($data)) === $data for your fixture shapes. This catches escaping and type-fidelity surprises early.

Gotchas and Tips

  • TOON is not JSON and models know it less well. Weaker or smaller models will occasionally hallucinate JSON-ish output. Include a two-line description of the format in your system prompt, or a single few-shot example. Verify output with the validator before decoding.
  • Decoding is strict. Free-text model output often arrives wrapped in markdown fences or with a preamble sentence. Strip fences and slice from the first key-like line before calling Toon::decode().
  • Type fidelity on round-trip. Numeric-looking strings, booleans, null, and empty arrays vs empty objects are the classic edge cases in any indentation-based format. If you have IDs like "007" or enum-ish strings, round-trip test them explicitly rather than trusting the default.
  • Delimiter and quoting hazards. Values containing your configured delimiter, leading/trailing whitespace, or newlines need quoting. If you control the data, prefer flat scalar columns; if you don't, run a round-trip test on the actual strings before trusting the output.
  • Key ordering matters for caching and diffs. Build associative arrays in a deterministic order so encoded strings are stable across requests — otherwise prompt caches never hit.
  • Savings are workload-dependent. Tabular, uniform data compresses well; a handful of small nested objects may see little or no gain. Benchmark before making a claim in a PR description.
  • Model/provider compatibility is a prompt-engineering concern, not a package concern. If you fall back to JSON for a given model tier, feature-flag the formatter rather than duplicating call sites.
  • Debugging: when a model misbehaves, log the exact encoded string to a file (not to Sentry, given size and PII) and paste it into the model's playground directly. Most "TOON doesn't work" reports are prompt-shape problems, not encoding bugs.
  • Extension points are thin by design. There's no plugin system — the intended extension point is your own wrapper around encode/decode plus the config options. That's appropriate for a format library, but it means your application owns concerns like redaction, truncation, and per-model token budgets.
  • Vendor risk: 0 dependents and a single maintainer. Pin the version in composer.json, keep the wrapper class as your seam, and avoid leaking Toon:: calls into domain code so you can swap the encoder if the package stalls.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus