1994/ghostwriter-core
Ghostwriter Core provides the shared Laravel/PHP foundations for Ghostwriter, including core services, configuration, and integration points for building AI-assisted writing workflows. It is a lightweight base package for related Ghostwriter modules.
1994/ghostwriter-core is no longer just a draft/prompt/provider core. It now spans four domains: Connections (a single resolver for every third-party credential, with an encrypted CredentialStore port, key health checks, and a watched-HTTP-client signal), Suggest edits (deterministic free checks plus a two-call LLM review/verify pipeline with code-side anchoring and validation), Content to revisit (scheduled scanning, ranked revisit queues, optional external link checks), and an SEO layer (site-wide link index, link proposals, meta generation, heading normalisation, slugs/filenames). It remains framework-free, so the strategic verdict is unchanged: it fits as an inner domain library behind our own application module, not as a turnkey Laravel package. The fit is now stronger on value (one dependency covers editorial QA, SEO assist, and provider/credential plumbing that we would otherwise build) and heavier on surface area (roughly a dozen new ports to bind). It remains a poor fit if the team expects service providers, Eloquent models, migrations, routes, or schedulable jobs.CredentialStore, ChecksKeys, LinkIndex, RevisitStore, EntrySource, LinkProbe, SeoWriter, RenderProfiles, EntryIndex, AssetAlt, SeoFields, and ProposedLinks. Several of these are content-model-shaped, not generic — the link index needs every routable page of the site, RevisitIndex needs save/delete hooks and a daily/weekly schedule, RenderProfiles needs template introspection, and EntrySource needs queryable content. That means the integration is really a content-model mapping project with a domain core inside it. The upside: the package ships Testing\FakeKeyCheck, InMemoryCredentialStore, InMemoryRevisitStore, MemoryEntrySource, MemoryEntryIndex, and contract test helpers, which materially de-risks adapter development and should be used as the acceptance harness for each binding.NOASSERTION remains an unapproved state, and the amount of code we would need to review, vendor, or fork has grown substantially. Second risk is contract churn: a single minor release added a dozen ports and many domain types, which signals active, fast-moving design; every upgrade becomes an adapter regression exercise. Third is cost and blast radius of the LLM pipelines: a single page now can involve a writer call, an seo-editor call, an seo-verifier call, a reviewer call, a verifier call, and reworder calls, with long pages split across multiple calls (ReviewInput::calls()). Token spend per page is no longer a constant we can estimate from word count alone. Fourth is new operational surface: encrypted secret storage and rotation, outbound HTTP probing of third-party links (ExternalLinkCheck, 500 requests/run, 1/sec/host), and daily index passes writing up to 20,000 rows per site. Mitigating signals are genuinely good: deterministic checks run with no model and no request, and SuggestionValidator/QuoteFinder/ScopedEditCheck/SourceCheck/Anchor\SentenceFit drop unanchored or fabricated edits in code rather than trusting the model — that is the right architecture for a trust-sensitive feature. Maturity signals are still thin (no visible community validation, no commercial support), though a 1.10.0 line and shared engine across three addons is better evidence of real use than the previous assessment had.CredentialStore expect encryption keys to be provided and rotated, and is the stored-key path multi-tenant safe? What are the SSRF and rate-limit expectations for HttpLinkProbe and ExternalLinkCheck in a hosted environment? Does KeyWatch require us to route all provider HTTP through a specific client abstraction, and what is the latency/observability cost? Which index/queue backends are assumed for LinkIndex and RevisitIndex at 20k rows/site and daily refresh? Can the SEO layer be adopted without the Suggest/Revisit layers, and vice versa? What is maintainer capacity and roadmap after 1.10.0?CredentialStore over Laravel Crypt/a secrets table (or Vault/KMS), ChecksKeys and LinkProbe over Laravel Http with timeouts and per-host throttling, SeoWriter/AI provider ports over queued jobs, LinkIndex/RevisitStore over our DB with scheduled commands, RenderProfiles/EntrySource/EntryIndex/AssetAlt/SeoFields/ProposedLinks over our content models. Use Filament resources or API controllers for the Connections page and Search section; the package supplies strings (en/de/fr/nl/es) but not the UI. If the team is on Filament, the Ghostwriter for Filament 1.2 addon is now the more credible path and should be evaluated before a direct core integration.Suggest\Findings::standard()), which need no model, no provider, and no request — they validate the contract style, the phrase/locale handling, and the Quiet/Quieted persistence model at near-zero cost and near-zero risk. Second slice: Connections with one provider, proving the credential resolver precedence (env/config wins over stored), encrypted store, and one KeyCheck. Third: Suggest edits for a single content type, behind a flag, with the verifier on. Fourth: SEO layer, which is the largest data-model commitment because it requires a full routable-page index and a daily pass. Last: Content to revisit and the opt-in external link check. Run the whole thing first as a time-boxed spike against a fork-free pinned release, and compare each slice against building it internally — the free-checks slice in particular may be cheap enough to reimplement.Linkable, LinkIndex, and RenderProfiles encode those assumptions. The release notes as supplied are truncated; complete the read (including docs/connections.md and the full changelog) before finalising any estimate.Linkable misclassification, external link false positives (mitigated by the two-strike rule), queue backlog during editorial peaks, and encryption-key rotation for stored credentials. Train product support on the distinction between "nothing to suggest" and "the check failed," and on which AI output requires human review before publish.HeadingFixer, SlugRules, FilenameRules, Stemmer) are cheap and CPU-bound; the scaling pressure is now threefold. (a) Tokens: multi-call pipelines with page splitting make cost per article variable and potentially several times the previous estimate — enforce per-tenant budgets, cap ReviewInput::calls(), make the verifier optional per plan, and cache Quiet::CHECKED. (b) Scheduled work: RevisitIndex daily plus a weekly full pass, LinkPlan writing up to 5,000 rows per group and 20,000 per site, and ExternalLinkCheck at 500 requests/run with 1/sec/host — this needs dedicated queue lanes, jitter, and backpressure so it never competes with user-facing jobs. (c) Storage: link index rows, revisit rows, drafts, job history, and audit of credential events all grow per site and per tenant; plan retention and partitioning early. Isolate credential stores, link indexes, and provider keys per tenant.LinkIndex producing bad link proposals or none; Linkable classifying a valid page as untargetable; credential resolver precedence surprising operators (env overriding a key someone just saved); key marked broken on a transient 5xx; external link probing hitting bot-blocking hosts or internal addresses if not egress-restricted; queue backlog from daily/weekly passes; DB growth from index rows; silent breakage of a port after an upstream minor bump. Mitigations: retries with backoff, circuit breakers, dead-letter queues, two-strike confirmation on link probes, egress allow-listing, health metrics per stage, and user-visible "assist unavailable" fallbacks rather than empty states. Licence ambiguity remains the highest-severity failure mode if discovered after adoption.How can I help you explore Laravel packages today?