Skip to content
Get started

Open source · Apache-2.0 · Version 1.0 is close

The CMS that AI can read, write and measure.

Built for the web that software reads and writes. Every page starts as a typed entity, so search engines, answer engines and AI agents all see the same thing. Agents publish through the same rules as your team, and you can see which AI read which page. Open source, in one Go binary.

docker compose up
Runs on
  • One Go binary
  • Postgres 16
  • htmx admin, no Node
  • WASM plugins
  • One docker compose up
Hatamoto AI analytics: AI fetches, verified share, spoofed hits, visits from AI assistants and pageviews, above a chart of AI crawler fetches per day by operator.

What ships in core

The plugin stack you'd normally assemble, already in the box.

Each of these comes with Hatamoto and reads from the same entity model. Your schema markup can't drift from your sitemap, and your sitemap can't drift from the page.

  • 01Content model

    Schema-first entities

    Content types are JSON Schemas with schema.org annotations and a URL pattern that can include dates and parent pages. Pages, posts, services and people are all entities.

    schemas · url patterns · taxonomies
  • 02Editing

    Page and blog editors that know your site

    A page builder with live preview, and a writing view with a slash menu, autosave, revisions and an SEO and answer panel. Entity links stay valid when a slug changes.

    builder · blog editor · revisions
  • 03AEO · GEO

    Built for answer engines

    Typed JSON-LD for every entity, FAQ and Claim markup, a public knowledge graph, and llms.txt with a per-page opt-out.

    json-ld · llms.txt · knowledge graph
  • 04SEO

    SEO from the same model

    Meta and canonical fields on every entity, redirects with wildcards, a 404 log, and internal links that add themselves from rules you set once.

    redirects · 404 log · internal linking
  • 05AI visibility

    Agent analytics

    See which AI crawlers and assistants fetch your pages, why they fetch them, and whether the traffic really comes from them.

    training · search index · user fetch
  • 06Agents

    Let AI agents work through the CMS

    An MCP server at /mcp and a CLI use the same services as the admin, with scoped API keys and an audit log of every call.

    mcp · cli · api keys
  • 07E-E-A-T

    People and bylines

    Every author is a person entity with a photo, job title, bio and profile links, published as Person JSON-LD on their profile and on every post.

    person · author pages · bylines
  • 08Measurement

    Analytics without a tracker

    Pageviews and AI referrals are counted on the server and rolled up daily in your own Postgres. No visitor profiles, no third-party script.

    pageviews · ai referrals · daily rollups
  • 09Performance

    Fast by default

    Pages are rendered by Go templates and served from an in-memory cache that clears itself when content changes, with preload from the sitemap.

    html cache · invalidation · preload
  • 10Discovery

    Sitemaps, feeds and robots in core

    A sitemap index with groups, a readable view for people, RSS and Atom feeds, and robots.txt with an AI crawler policy.

    sitemap index · rss · atom · robots.txt
  • 11Site basics

    Forms and menus

    A form builder with ten field types, spam protection, email notifications and CSV export, plus nested menus placed where your theme shows them.

    forms · submissions · menus
  • 12Assets

    Media library

    Upload once. Hatamoto checks the file, creates resized WebP variants, and you pick images straight from the editor.

    variants · webp · validation
  • 13Updates

    Updates that roll themselves back

    Signed releases install in your maintenance window. If the site fails its checks afterwards, the previous version comes back on its own.

    signed · channels · auto rollback
  • 14Plugins

    Sandboxed plugins and themes

    Plugins are WebAssembly modules with their own Postgres schema and only the permissions you grant. Signed packages install without a restart.

    wasm · permissions · signed packages
  • 15Migration

    Bring your WordPress site

    Import from the REST API or a WXR export. Old URLs keep working, SEO titles carry over, and a URL audit checks every old address.

    rest · wxr · url audit

Why entities first

Search engines and LLMs read structure. Write it once, at the source.

Most CMSs store a page as a block of HTML and leave plugins to guess what it means afterwards. One plugin adds the schema markup, another builds the sitemap, and a third writes llms.txt. They all read the same page and they all reach slightly different conclusions.

Hatamoto works the other way round. You describe the thing first, for example a service, a location or a person, and say which schema.org type it is. The public page, the structured data, the sitemap entry and the AI summary are all generated from that one record, so they can't contradict each other.

Typed fields, not page soup

Fields are validated against the schema when you save. Rich text is sanitised on the way in, so it stays clean even when a plugin edits it through the entity.before_save filter.

URLs are part of the model

Each schema owns its URL pattern, including dated and nested paths. Archives and canonical URLs are worked out from the model, and redirects are written for you when content moves.

Content type settings: address pattern, archive address, archive title and breadcrumb label.

Each content type owns its address pattern, archive and structured data type.

AEO · GEO · SEO

Rank in search. Get cited in answers.

Classic SEO and AI answer visibility need the same thing: clean, structured, verifiable content. Hatamoto handles both from the core.

JSON-LD
Generated from the schema for every entity, with FAQPage, Question, Answer and Claim markup. Plugins can enrich it through the jsonld.enrich filter.
llms.txt
Served from the same model, with a summary for each entity and a per-page switch for content you'd rather leave out.
Knowledge graph
A public endpoint that shows how your entities relate to each other.
Internal linking
Pair a phrase with a target page once and it's linked across your content. Suggestions and a link equity view show the gaps.
Redirects
Admin-managed 301, 302, 307 and 308 rules, with wildcards and a 404 log so nothing slips through.
Search Console
The first-party Search Console plugin connects your property with OAuth, submits sitemaps and imports performance data.
GET /services/emergency-plumbingrendered head
<!-- generated from the entity, not a plugin -->
<link rel="canonical" href="…/services/emergency-plumbing">

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    { "@type": "Service",
      "name": "Emergency plumbing",
      "areaServed": "Melbourne" },
    { "@type": "FAQPage",
      "mainEntity": [{
        "@type": "Question",
        "acceptedAnswer": { "@type": "Answer" }
      }] }
  ]
}
</script>
/sitemap.xml
index + groups
/llms.txt
entity summaries
/knowledge-graph
public JSON

Agent analytics

Know when an AI reads your page, and why.

Hatamoto logs AI crawler visits on the server, with no JavaScript tracker. Each hit is sorted by purpose, the bot's IP is checked against the operator's published ranges, and every fetch is tied to the entity it hit.

Training

Model crawlers

Bulk crawls that feed future models. Allow or block them in robots.txt, right next to the data.

  • GPTBot
  • ClaudeBot
  • CCBot

Search index

Answer-engine indexers

Crawlers that build the indexes AI search answers from. If they don't fetch a page, it can't be cited.

  • OAI-SearchBot
  • Claude-SearchBot
  • PerplexityBot

User fetch

Live assistant requests

Someone asked an assistant a question and it opened your page to answer. This is the signal that matters most.

  • ChatGPT-User
  • Claude-User
  • Perplexity-User

Verified, not guessed

The IP is checked against published ranges and confirmed with reverse DNS. Spoofed user agents are flagged.

Per entity

The blog editor shows AI crawler activity for the post you are writing.

First crawls

See when each agent first fetched a new or updated page.

AI referrals

Visits from chatgpt.com, perplexity.ai and claude.ai are counted per assistant and per day.

AI crawler agents table: GPTBot, OAI-SearchBot, ClaudeBot, PerplexityBot, ChatGPT-User and others, with operator, purpose, fetches, verified share and last seen.

Every agent by name: who runs it, why it fetched your pages and how much of its traffic was verified. Demo data.

AI publishing

Software will do more of your publishing. Most CMSs aren't built for it.

Within a few years an AI agent will draft the weekly post, refresh the prices on a service page, add a new suburb to a location page and fix the broken link a crawler found overnight. A CMS built for one person clicking buttons in a browser has no safe way to let it.

Typical CMS

Built for one person in a browser

  • One admin password, or an API key that can change everything
  • An agent's edit goes straight to the live page
  • Content is a block of HTML the agent has to guess its way through
  • No record of what the agent changed, or why
  • Undoing a bad edit means restoring a backup

Hatamoto

Ready for agents today

  • An MCP server at /mcp, with a scoped key for each agent
  • Anything an agent creates starts as a draft
  • Typed schemas the agent can read before it writes
  • Every call, allowed or refused, written to an audit log
  • Every save is a version you can restore in one click

Let AI agents work through the CMS

An MCP server and a CLI, with the same rules as the admin.

Agents call the same services as the admin, so validation, slug rules, HTML sanitising, plugin hooks and cache invalidation behave the same whoever makes the change.

Scoped keys
A read:entities key can't call a write tool. Media, menus and redirects need their own write scopes.
Drafts first
entities_create always makes a draft. Destructive tools are marked, so clients can ask before running them.
Audit log
Every call, allowed or refused, is logged, and changes are tagged [mcp:key name] in the version history.
Checks
Agents can preview the sitemap and llms.txt, validate JSON-LD and read AI crawler stats.
MCP client config
{ "mcpServers": {
    "hatamoto": {
      "url": "https://example.com/mcp",
      "headers": {
        "Authorization": "Bearer nxk_…" } } } }
New API key form with access scopes such as Read entities, Write entities, Write media, Write menus and Write redirects.

One key per agent, with only the access it needs.

Page and blog editors that know your site.

Posts open in a calm writing view with a slash menu, autosave, revisions, FAQ and callout blocks, and an SEO and AEO panel with fourteen search and answer checks. Pages open in a builder with a structure tree, a live preview at desktop, tablet and phone sizes, and an inspector. Both save to the same entity, so the structured data keeps up with whatever you write.

The blog editor with a post open, a formatting toolbar and a side panel for status, schedule, slug and featured image.

E-E-A-T

Real authors on every post, in a form search engines can check.

Google's quality guidelines weigh who wrote a page and why they're qualified to. In Hatamoto every author is a person entity with a name, photo, job title, short bio and profile links.

First sign-in
Everyone who logs in completes their profile, so no post goes out with a blank byline.
Guest writers
Add people without giving them a login.
Profile pages
Each person gets a public profile page only if you switch it on.
Organisation bylines
Posts written by the business credit your organisation instead of a person.
/author/ajay-chavdaPerson JSON-LD
{
  "@type": "Person",
  "@id": "https://hatamoto.dev/author/ajay-chavda#person",
  "name": "Ajay Chavda",
  "jobTitle": "Founder",
  "worksFor": { "@id": "https://hatamoto.dev#organization" }
}
The People list with name, job title, login, public profile and post count.

The same @id appears on the profile page and in the author field of every post that person wrote.

The plugins you'd normally install are already part of core.

Each one uses the same content model, has its own screen in Settings and updates with everything else. There are no banners, upsell notices or licence keys.

Updates that roll themselves back

After an update, Hatamoto checks your home page, sitemap, a published page and the admin login for a minute. If any of them fails, the previous version comes back and the database is left alone.

Updates status: Rolled back v0.26.1, smoke failed: GET /contact returned 500.

A page cache with nothing to set up

Cached pages are served from memory in a few milliseconds. The cache clears when you save, and it can preload every page in your sitemap. No Redis or Varnish.

Page cache settings: on, keep pages for 30 days, max cache size 200 MB.

Internal links that add themselves

Pair a phrase with a target page once. Hatamoto links it across your content, with a priority and a limit per page.

Internal linking rules: phrases, the pages they link to, and their priority.

Menus

Drag items into order, indent them to make sub-menus, link them to pages or any address, and place each menu where your theme shows it.

Menu editor with Home, About, Blog and Contact items.

Forms and submissions

Ten field types, a hidden spam trap instead of a CAPTCHA, email notifications and CSV export. A signed webhook can send each submission to your CRM.

Form submissions for the Contact form with an Export CSV button.

Redirects and a 404 log

Rules with wildcards, a log of missed addresses, and Explain a URL to show which rule will answer a request.

Redirect rules list with from, to, type, hits and state.

Built in, not bolted on

One model instead of a plugin stack.

Every plugin you add brings its own settings screen, its own update schedule and its own idea of what the page means. Hatamoto keeps all of that in one place.

Assembled

A typical page-builder CMS

  • An SEO plugin for meta and canonicals
  • A schema plugin guessing JSON-LD from HTML
  • A sitemap plugin with its own exclusions
  • A cache plugin that has to be told what changed
  • A third-party analytics script, with consent banner
  • Server logs you never read for AI crawlers

Hatamoto

One entity model in core

  • Meta and canonicals from the entity model
  • JSON-LD generated from the schema.org type you chose
  • Sitemaps and llms.txt from the same records
  • An in-memory page cache that clears itself when content changes
  • Pageviews and AI referrals counted on the server
  • AI agent visits tracked on the server

Plugin SDK

Extend it with sandboxed plugins.

Plugins are WebAssembly modules built with the standard Go toolchain against hatamoto.dev/sdk, or in any language with an Extism PDK. They get typed hooks, their own Postgres schema and only the permissions you grant.

  • entity.publishedaction, after commit
  • entity.before_savefilter; reject with a reason for a 422
  • jsonld.enrichfilter on generated JSON-LD
  • sitemap.urlsadd entries to the sitemap
  • render.pagerequest-aware filter: hide or replace blocks
  • form.submittedaction with the submission

Plugins can also ship migrations, a settings form generated from a JSON Schema, routes, cron jobs and an admin page in a sandboxed frame. They install as signed packages without a restart, and a failing plugin never takes the site down.

plugins/hello/main.goGo
package main

import (
  "hatamoto.dev/sdk"
  "hatamoto.dev/sdk/guest"
)

func init() {
  guest.OnAction(sdk.EntityPublished,
    func(ev sdk.EntityEvent) error {
      guest.Log(guest.LogInfo, "published "+ev.Slug)
      return nil
    })
}

//go:wasmexport on_entity_published
func onEntityPublished() int32 {
  return guest.Run(sdk.EntityPublished.Export())
}

func main() {}
Installing the gtm plugin: signed by a key, with a permissions list you can untick before install.

Installing a plugin: signed, versioned, and nothing granted that you didn't tick.

Quickstart

Running locally in one command.

The first boot starts Postgres, generates and saves your secrets, runs every migration and prints a one-time setup code.

  1. 01

    Clone and boot

    Two services start: db and hatamoto.

    git clone https://github.com/zenlabscorp/hatamoto
    cd hatamoto
    docker compose up
  2. 02

    Grab your setup code

    The setup code is printed once to the logs.

    docker compose logs hatamoto
  3. 03

    Create your site

    Finish the setup wizard, then start empty, add starter content or import from WordPress.

    open http://localhost:8090/admin

Questions

What does schema-first mean in Hatamoto?

Every content type is a JSON Schema annotated with a schema.org type. Pages, JSON-LD, sitemap entries and llms.txt summaries are all generated from the same typed record, so they stay in sync.

Do I need plugins for SEO, sitemaps or caching?

No. Meta and canonical fields, redirects, a 404 log, internal linking, sitemaps, feeds, llms.txt, page caching, forms, menus and server-side analytics all ship in core.

What is agent analytics?

Server-side tracking of AI crawlers and assistants. Each hit is sorted by purpose (training, search index or a live user fetch), verified against the operator's published IP ranges and reverse DNS, and reported per page.

How do plugins work?

A plugin is a WebAssembly module built with the Go SDK, hatamoto.dev/sdk, or any language with an Extism PDK. It subscribes to typed hooks, can ship migrations, routes, cron jobs and a settings form, and runs in a sandbox with only the permissions you grant.

What does Hatamoto run on?

One Go binary and Postgres 16. docker compose up boots both locally. In production the binary runs its own migrations and serves the site, the admin, the API and MCP on one port, with a supervisor that restarts it if it crashes.

Can I move my WordPress site?

Yes. The importer reads the REST API or a WXR export, keeps your URL structure, carries SEO titles over from Yoast, Rank Math or SEOPress, and audits every old URL so it returns a page or a single redirect.

Is there a Node build step or a JavaScript framework?

No. Public pages and the admin are rendered on the server from Go templates. The admin uses htmx, and editor code loads only on the screens that need it. There's nothing to build with npm.

How do updates and rollback work?

Releases are signed and published to an edge or stable channel. Hatamoto installs them in your maintenance window, keeps the previous binary, and checks the site for a minute after switching. If the checks fail it switches back on its own. Database changes are written so the previous version can still run on them.

Does it send any data home?

No telemetry. The only outbound call is an update check, one anonymous request for a signed file, and you can turn it off with HATAMOTO_UPDATES=off.

Stand close. Serve well.

An open-source CMS for teams who want to be found by search engines, cited by AI and ready for the agents that will publish alongside them.

Try it in five minutes