πŸœ›
stdlib python your claude subscription no api keys

Bring a domain name.

Nothing else. Alkeyword reads the site, mines the questions people actually ask, measures what AI engines say back β€” and hands you research briefs built from your own claims. You write. It does everything before that.

Runs on your machine, on your Claude subscription. The crawl is plain Python and costs nothing. Every panel on this page is real output β€” you can regenerate all of it from the download.

/alkeyword opensentience.org

    

Stage 1 output, verbatim, from a real crawl of a live site. Deterministic Python β€” no model was called to produce any of it.

the premise

Transmute, never fabricate

Alchemy transmutes existing material. It does not conjure from nothing β€” and neither does this. That single constraint is what the whole tool is built around, and it is why this page can be made of real output instead of screenshots of a demo.

Every autoblog tool

Guesses your niche and writes net-new articles about it. That is why the output is generic, why it gets facts about your business wrong, and why it trips Google's scaled-content-abuse detection.

Alkeyword

Does the research and stops. Every number, price, process and quote your site already publishes, matched to the questions people really ask β€” handed to you as a brief. Nothing is invented, because nothing is written.

the live explorer

Twenty real sites. Pick one.

This is not a mockup and it is not sample copy. It is stage-1 output from an actual crawl of our own portfolio β€” 100 pages, 77,859 words, 4,506 claims β€” rendered by the same numbers the terminal prints. Two more surfaces were crawled and dropped here because they returned nothing; one 404s and one does not resolve, which is itself a finding.

entityβ€”
pagesβ€”
wordsβ€”
claimsβ€”
claim graph by type

Rows are ordered by measured citation value, not by count β€” quantity is the strongest lever whether or not it is the largest bar.

material sufficiency β€” what could be minted
free findings β€” no engine calls spent
raw material β€” real claims, verbatim

Regenerate every number above with python3 prototype/runs/site_dataset.py. It reads the crawl JSON and refuses to build if crawl.py's thresholds have drifted from the ones this page publishes.

the load-bearing rule

It will tell you it can't.

Every form has a material threshold. Below it, the tool refuses to generate and says exactly what is missing β€” and the refusal is not a warning you can click past, it is the answer. Drag the slider and watch the verdict flip at the threshold. These are the real numbers from crawl.py Β§4.2, not illustrations of them.

Claims of this type your site actually has 0
refused

This is deliberate, and relaxing it under revenue pressure is the one change that would turn this into the thing it was built against.

Worth being precise about what the risk actually is, because the scary version is wrong. Google does not prohibit AI-assisted content. Its scaled content abuse policy β€” introduced with the March 2024 spam update β€” targets producing many pages primarily to manipulate rankings, and says so β€œno matter how it's created.” Human, automated or generated is not the test; volume of low-value pages is. So a tool that hands one person one grounded brief is not walking up to that line, and a tool that publishes thirty a month is, regardless of who typed them.

what it does

Crawl β†’ expand β†’ probe β†’ brief

Research without a target is just a dashboard, and dashboards are what people churn out of. Every brief carries the raw material with it, so writing is assembly β€” not another research job handed back to you.

Deterministic, free, and where everything starts. Fetches the site with the standard library only β€” there is nothing to pip install β€” and builds a typed claim graph plus six findings that cost no model calls at all. If robots.txt blocks AI crawlers it stops here and says so, because nothing downstream matters until that is fixed.

python3 crawl.py opensentience.org --json crawl.json

        
a real finding, both halves measured

Predicted for free. Confirmed for $0.015.

The crawl noticed one number stated prominently and a different, correct number stated once and buried. It did not need an engine to see that β€” it is a positioning fact, visible in the claim graph. Both of these are real claims from the same site, pulled straight out of the crawl by the same code that built the explorer above:

The second one looks like scraped noise, and that is the finding rather than a flaw in the excerpt. It is the site's own navigation β€” β€œThe 103 laws” as a link label, on every page. The correct figure appears once, in a sentence, on one page. Four prominent placements against one buried one; an engine weighs position, not correctness.

From signal dominance alone, stage 1 predicted the engine would learn the wrong total. Stage 2 asked, three times:

β€œOpenSentience's homepage says the box-and-box kernel has 103 laws Γ— 2,000 trials.”

perplexity/sonar β€” 3 of 3 runs, citing opensentience.org. The authoritative number is 116.

A true fact, positioned so weakly the model learned the wrong one. No keyword tool surfaces that, because it is not a keyword problem β€” it is a signal-dominance problem, and you can only see it by comparing what a site says against what engines repeat back.

The same run turned up something a single-site crawl structurally cannot see: a second property, under the same owner, told the engine 15 laws Γ— 1,000 trials. Three numbers, three sources, and the engine returns whichever page it lands on.

v0.6.0, v0.6.1 and v0.6.2 Β· the tool caught itself, three times

It published a gap that did not exist

Three days ago this crawler reported that our three documentation hosts served one document with no canonical between them, and filed the fix as a portfolio work item: pick one canonical host, 301 the others.

It had never parsed <link rel="canonical">. The word appeared once in the entire crawler, inside a docstring. All three hosts already declared <link rel="canonical" href="https://docs.ampersandboxdesign.com/">. The work item was an artifact of a tool asserting the absence of something it had never looked for.

An unevidenced claim is not safe just because it happens to be true. Of the nine within-host duplicate groups, all nine really were missing a canonical β€” the guess was right every time it went unpublished, and wrong in the one case that became a work item.

Being right by luck is not being right, and it is not a reason to keep guessing.

What changed: canonical is now an observation. Each URL's declared target is recorded, and a duplicate group reports agree, disagree, partial or absent. Disagreement is the case worth having and the old wording could not express it β€” two URLs each naming themselves as the original is a worse problem than neither doing so.

The retraction is published in the same document that carried the claim, by name, because a quiet correction is a second error. Three other faults were repaired in the same release: claim anchors pointed at the page's last heading rather than the section the claim came from, robots.txt was read case-sensitively so a lowercase user-agent: gptbot blocking everything registered as unblocked, and the configuration layer described limits the running code never read. Each has a regression test that was watched failing first.

Then it happened again, one release later, in a subtler form. The robots repair delegated to Python's urllib.robotparser and a code comment credited it with standards-level rule handling. That was true on the machine it was written on and false on four of the five interpreters we tested β€” 3.9 through 3.12 have no longest-match precedence, no wildcards and no end anchors; 3.13.14 has all three. Same error class as the canonical bug: a capability asserted rather than observed, this time because the standard library sounded authoritative. The rules are implemented locally now, every artifact records which engine produced it, and five more tests pin the semantics so the answer cannot depend on which Python a reader happens to have installed.

And a third time, for the least flattering reason of the three: nobody had ever run the whole pipeline in one pass. Every stage had tests, the corpus had twenty-two sites in it, and the loop from crawl to brief had never once been walked end to end against a live site. Doing that took under a minute and found three defects no unit test could reach. The worst: brief.py keyed probe results by question ID and then looked them up by question text, so the two never met β€” measuring what engines said about you contributed nothing to any brief, silently, and the rule that treats a measured citation miss as the strongest signal available was unreachable code. Alongside it, the line naming which engine a rate was measured on had that engine's name hard-coded, and the function that reduces a URL to a comparable domain stripped www. with lstrip β€” which removes characters, turning a bare wikipedia.org into ikipedia.org and an encyclopedia into a competitor.

A test suite is evidence that the parts agree with themselves. It is not evidence that the thing runs.

Three green stages, one dead join between them, and fifteen passing tests.

Three more regression tests, each watched failing first. The same release also made the download archives build from a script that unpacks what it just built and diffs it against the tree β€” which immediately caught stray bytecode caches riding along inside the shipped tarball, visible only because the archive came out 68% heavier than the release before it.

the part that is honest about its own limits

The extractor has a ceiling, and the tool says so

The Python claim extractor is heuristic and has one root failure: it does not resolve subjects. So it over-fires on definition, dumps most claims into attribute, and cannot trust its own contradiction detection. That is not a footnote β€” it changes the output enough that the tool tells you to supply the seeds yourself. Measured on a live site, identical code and identical claim graph, only the seeds differing:

βœ“ ready0
~ thin3
βœ— none312

what it looks for

Ten gap types, ranked by what fixing them is worth

Ranked by reach Γ— winnability Γ— material_sufficiency Γ· effort. Three of them need no generation at all β€” they are link and markup fixes that cost nothing and are found for free.

G1Dark factThe site states it; the engine never surfaces it. Mint a page where it is the headline answer.
G2Wrong factThe engine asserts something the site contradicts. Highest urgency β€” but check the site's own dates first, because model staleness is not the same as an error.
G3Ceded questionA competitor is cited, you have the material, and no page exists. The primary generation trigger.
G4Unsupported claimA claim with no number and no source behind it. Strengthen it with the site's own figures.
G5Missing formMaterial exists for a high-citation page type that was never built.
G6Self-contradictionTwo claims on the site conflict. Resolve it before generating anything at all.
G7OrphanA valuable page with almost nothing linking to it. Internal linking β€” no generation needed.
G8Thin entityNo schema, no author, no about page. Nearly free to fix, and portfolio-wide.
G9Blockedrobots.txt blocks AI crawlers. Nothing downstream matters until this is cleared.
G10Duplicate URLsThe same content served at more than one URL, splitting authority between them. Found by the crawl, added to the spec because live input surfaced it.
what it costs

Your subscription, not a meter

StageRuns onCost
Crawl, claim graph, free findingsYour machine, plain PythonNothing
Keyword and question expansionGoogle + DuckDuckGo autocompleteNothing, no key
Extraction, probing, generationYour Claude subscriptionSubscription usage
Multi-engine probing (optional)Your own API keysReal per-probe cost, quoted first

No keys to paste for the default path, no per-token bill. The parts that are expensive to compute are deterministic code; the model is used only where judgment is actually needed.

One caveat, stated plainly. Probing through your Claude session covers the web-search surface it reaches β€” that is one engine. Cross-engine citation overlap is only about 11%, so it implies nothing about ChatGPT, Perplexity or Google AI Overviews.

Engines are never blended into one score. Rates are reported per engine, or not reported.
v0.6.2

Where this actually is

There is no testimonial wall on this page and no logo strip, because a tool that refuses to fabricate output cannot fabricate its own marketing. So here is the honest state, in the same three categories the tool would use.

measured Stage 1 β€” crawl and free findings Run against 22 live surfaces. 20 returned pages; 4,506 claims and every finding on this page came out of it. Fifteen regression tests cover the four faults v0.5.0 shipped and the one v0.6.0 introduced, each watched failing before its repair.
run once, for real Stages 2–4 β€” expand, probe, brief Expansion mined 457 real queries. The probe was a real paid run: 27 calls, $0.1424, one engine. Enough to confirm the thesis end to end; not enough to call any of it a rate across engines.
not yet Stage 5 β€” calibration Turning form values into measured priors needs a published brief with probes on both sides of the publication date. Nothing has been published yet, so calibrate.py correctly reports nothing rather than inventing a trend.

The known ceiling is named above and in the skill file that ships with it: the heuristic extractor cannot resolve subjects, and that single fault is the root cause of all four of its failure modes.

install

Download

A Claude Code skill plus eight Python files. No package manager, no build step, no lockfile, nothing to pip install β€” the standard library and a Claude Code session you already have.

terminal
tar xzf alkeyword-0.6.2.tar.gz
cd alkeyword
./install.sh

# then, in a new Claude Code session:
/alkeyword yourdomain.com

Requires Claude Code and python3. ./install.sh --project installs into one repo instead of your user account. There is no Alkeyword server and no Alkeyword account: every artifact it produces lives in ~/.alkeyword on your machine. Requests do leave the machine, and they go where the analysis requires β€” the site being crawled, Google and DuckDuckGo autocomplete, and whichever engine you probe. Nothing is routed through us, because there is no us to route it through.

The research is the product.
The writing is yours.

Bring a domain name. Get back what your own site already proves, matched to what people are actually asking β€” and an honest refusal where the material isn't there.