Skip to content

AI Writer ​

Your own AI key for translations and other texts the modules write.

kitloom/ai-writer · admins: kitloom/ai-writer-filament, kitloom/ai-writer-nova

Video lessons ​

Recorded in the Filament admin; the Nova admin works the same way.

Set up AI Writer

Your own AI model for the texts the site's modules write for you: a translation of a post, a meta description, an image's alt text. You choose the provider, paste its API key and set how much a month may be spent; the modules ask, the provider bills you for what they ask, and every question is written down with what it cost.

The admin is kitloom/ai-writer-filament or kitloom/ai-writer-nova: the AI Writer section with Usage, Settings and this page.

This is the site asking a model with its own key. Connecting your own AI agent (Claude, ChatGPT, Cursor) to the site is a different thing: that is kitloom/ai, which needs no key here and costs nothing on the site's side.

Setting it up ​

  1. Get an API key from the provider: for Anthropic (Claude) at console.anthropic.com → API keys. Keep its billing limit there too — the budget here is a second fence, not the only one.
  2. AI Writer → Settings: pick the Provider, paste the API key, leave Model empty for the provider's cheapest text model (Claude Haiku for Anthropic, plenty for translations and descriptions) or name another, and set a Monthly budget.
  3. Press Test the key (on Settings in Filament, on Usage in Nova): the model is asked one short question, and the answer — or the provider's error — is shown.

The key is encrypted with the application key before it is saved and never shown again; leave the field empty to keep it. If the application key changes, the saved key no longer decrypts and has to be entered again. Until a key is saved on the page, the provider, key and model from the server's .env are used (see Configuration).

What it costs, and the budget ​

  • Every question is a row of Usage: when, what for (languages.translate, seo.description, ai-writer.test), who asked, the model, the tokens in and out, and the cost in US dollars. A question that failed is there too, with the provider's error.
  • The cost is counted from the prices in kitloom-ai-writer.prices (US dollars per million tokens): every provider's cheapest text model is there, and the common others — Claude Haiku, Sonnet, Opus and Fable; OpenAI's GPT-6 and smaller GPT-5 models; Gemini; Mistral; DeepSeek; Grok; the OpenRouter defaults. A provider that bills a long prompt at a higher rate (Claude Haiku past 100K tokens, OpenAI past 272K) is counted at that rate. Where a price is higher at some hours or from a date already announced, the higher one is listed, so the budget stops early rather than late.
  • The Monthly budget counts from the first of the month at the site's midnight (Settings → General → Timezone). Once the month's questions cost that much, the modules get no more answers — their buttons disappear — until the next month, or until you raise the budget. Empty — no limit.
  • A model whose price is not listed cannot be counted. While a budget is set it is not asked at all — its buttons disappear and "Test the key" says why — since the budget could never stop it. Without a budget it is asked and logged by its tokens, its cost shown as Price unknown. Either way the settings page and Usage say so: add its price to kitloom-ai-writer.prices (published config), name a model that has one, or clear the budget.
  • The figure is an estimate from the tokens the provider reports; the provider's own invoice is what you pay.

Who sees it ​

One permission, Manage AI Writer (manage_ai_writer), covers Usage and Settings: the key and the budget are your money. Administrators have it. Modules that ask the model check their own permissions — an editor a module lets use its "with AI" button uses it without seeing the key.

AI agents ​

With kitloom/ai installed, an agent whose user has manage_ai_writer reads what Usage sums (ai_writer_usage): this month's spending against the budget, the questions of unknown price, the sums by purpose and model, and the latest failures with the provider's error. Not the key, and not who asked. It changes nothing: the provider, the model and the budget are settings a person changes. kitloom-ai-writer.ai.register false — no such tool.

Personal data ​

With kitloom/privacy, Tools → Export Personal Data lists the questions the user the address belongs to asked: when, what for, the provider and model, the cost and an error if there was one. What was asked and answered is not kept, so it is not in the archive either. Erase Personal Data takes the user off their questions (user_id empty) and keeps the rows: the month's budget and Usage are their sums, and deleting them would hand the money already spent back to the budget. Usage shows those questions without a name.

Where things are kept ​

WhatWhere
Usagetable ai_writer_usage (the site's table prefix in front), model Kitloom\AiWriter\Models\Usage
Settingsoptions ai_writer_provider, ai_writer_key (encrypted), ai_writer_model, ai_writer_monthly_budget
Configurationconfig/kitloom-ai-writer.php

Configuration ​

config/kitloom-ai-writer.php of the package, merged into the application (php artisan vendor:publish --tag=kitloom-ai-writer-config).

KeyEnvironmentDefaultWhat
provider, key, modelKITLOOM_AI_WRITER_PROVIDER, KITLOOM_AI_WRITER_KEY, KITLOOM_AI_WRITER_MODELanthropic, —, —Used together while no key is saved on the settings page
monthly_budgetKITLOOM_AI_WRITER_MONTHLY_BUDGET—US dollars, while none is saved on the page
budget_ceilingKITLOOM_AI_WRITER_BUDGET_CEILING—US dollars a month no budget saved on the page goes past, nor an empty one — for a site whose administrators are not the ones who pay, such as a public demo; the settings page says so
providers—Anthropic, OpenAI, Gemini, Mistral, DeepSeek, xAI, OpenRouterWhat the page offers: laravel/ai driver => label
prices—The listed providers' modelsUS dollars per million input and output tokens, by model; long — the rate past above prompt tokens. A published config replaces the whole list
timeout, max_tokens—120, 16000Seconds to wait for one answer, and the most tokens it may have
filament.register, nova.register—trueWhether the admin section is added
privacy.register—trueWhether the personal data export and erasure are tagged for kitloom/privacy

For developers ​

The module binds Kitloom\WpSchema\Contracts\TextGenerator. A module that writes text asks the contract, never this package, so it works — without its buttons — on a site that does not install AI Writer:

php
use Illuminate\Contracts\JsonSchema\JsonSchema;
use Kitloom\WpSchema\Contracts\TextGenerator;
use Kitloom\WpSchema\Text\TextGenerationFailed;

$writer = app(TextGenerator::class);

if ($writer->available()) {               // a key is set and the budget not spent: draw the button
    try {
        $fields = $writer->generate(
            'Translate the fields into French (Canada). Keep the HTML.',
            json_encode(['title' => $post->title, 'content' => $post->content]),
            fn (JsonSchema $schema): array => ['title' => $schema->string()->required(), 'content' => $schema->string()->required()],
            purpose: 'languages.translate',
            actor: $user,
        );
    } catch (TextGenerationFailed $e) {
        // say $e->getMessage() to the person who pressed the button; nothing was saved
    }
}
  • The instructions and the text go apart (system prompt and user message), so a text that says "ignore the above" is only text.
  • Without a schema the answer is a string; with one, an array of those fields.
  • The provider is built for each question from what is saved now, never from config/ai.php; laravel/ai's own config is not needed.
  • In tests, fake the provider: Kitloom\AiWriter\Prompting\TextAgent::fake(['Bonjour']) (StructuredTextAgent::fake([[...]]) for a schema).

What the application overrides ​

  • The model: ModelRegistry::use(Usage::KEY, App\Models\AiUsage::class) in a provider of the application; the package's own is used only when the key is free, and the admins read the class from the registry.
  • The writer itself: bind your own TextGenerator after the package's provider.
  • The admin sections: kitloom-ai-writer.filament.register and kitloom-ai-writer.nova.register turn them off.

Tests ​

From the application that installs the package: php vendor/bin/phpunit --testsuite AiWriter.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]