How to Connect Codex to WordPress.com and Post from Termux on Android

AI WORKFLOWS · 2026
Connecting Codex to WordPress.com from Termux on Android, debugging MCP and OAuth errors, and keeping publishing under human control.

You can run Codex from an Android terminal and connect it to WordPress.com through the Model Context Protocol (MCP). This guide documents not only the successful setup, but also the connection failures encountered along the way: an incorrect endpoint that returned HTTP 404, an OAuth callback that depended on Termux remaining open, credentials that did not persist into a fresh process, and WordPress sites whose plans or connection states limited the available tools.

The example device is a Samsung Galaxy S26 Ultra, although the workflow applies to other Android phones capable of running a maintained Termux build. The important parts are the Codex CLI, the exact MCP endpoint, a working OAuth credential store, and a deliberate draft-first publishing workflow.

Using Claude instead? See Publishing to WordPress with Claude and the WordPress MCP Connector for the corresponding browser-based Claude workflow, WordPress HTML constraints, and reusable-skill approach.


1  ·  What You Need
  • An Android phone with Termux installed from a trusted source such as F-Droid or the official Termux GitHub releases.
  • Node.js, npm, and Git in Termux.
  • An OpenAI account and the Codex CLI.
  • A WordPress.com account with permission to edit the target site.
  • A WordPress.com site whose plan and MCP settings permit the content tools you need.

Avoid an obsolete Termux package from an unofficial source. MCP availability is also site-specific: one account can contain a usable paid WordPress.com site, a site requiring a plan upgrade, and disconnected Jetpack sites at the same time.

2  ·  Install Codex in Termux

Update Termux and install the prerequisites:

pkg update
pkg upgrade
pkg install nodejs git

node --version
npm --version

Install and verify Codex, then start it and complete the sign-in flow:

npm install -g @openai/codex
codex --version
codex

Android may open authorization in the default browser. Return to Termux when the browser step completes.

3  ·  Add the Exact WordPress.com MCP Endpoint

Enable the WordPress.com MCP tools for your account, granting only the capabilities you need. Then register the remote Streamable HTTP server in Termux:

codex mcp add wpcom-mcp --url https://public-api.wordpress.com/wpcom/v2/mcp/v1
codex mcp get wpcom-mcp
codex mcp list

The exact path matters. The working endpoint used in this session was:

https://public-api.wordpress.com/wpcom/v2/mcp/v1

The saved configuration should be enabled, use a Streamable HTTP transport, and contain the complete /wpcom/v2/mcp/v1 path. Codex stores MCP configuration in ~/.codex/config.toml by default.

🔐 Keep Termux running during OAuth, and never paste an access token into a prompt.

Start authentication with codex mcp login wpcom-mcp. The browser redirects to a temporary callback on 127.0.0.1, so the Codex process in Termux must remain alive to receive it.

After approval, start a fresh Codex session and verify the server again. Treat ~/.codex as private configuration and never commit it to a public repository.

4  ·  Problems Encountered and How to Debug Them

HTTP 404 during MCP initialization. The first failure looked like this:

MCP startup failed
unexpected server response: HTTP 404
when send initialize request

The configured URL was an incomplete WordPress.com API path, not an MCP endpoint:

https://public-api.wordpress.com/wpcom/

Inspect the registration with codex mcp get wpcom-mcp. If it is wrong, replace it cleanly and authenticate again:

codex mcp remove wpcom-mcp
codex mcp add wpcom-mcp --url https://public-api.wordpress.com/wpcom/v2/mcp/v1
codex mcp login wpcom-mcp

Browser approval succeeded, but the next session was unauthenticated. Symptoms included AuthRequired at startup, Auth: Unsupported in the MCP list, or a success message followed by failure in a fresh Codex process. That is a credential-persistence problem, not an endpoint problem.

Android Termux could not reliably store the OAuth token. In this session, the browser-based WordPress authorization completed successfully, but the Android Termux environment could not reliably save the OAuth token in a form that a later Codex process could retrieve. The clearest symptom was try_lock() not supported when Codex attempted to use its file-backed credential store. As a result, a fresh session could return AuthRequired even though the browser had just reported a successful login. This was a local credential-storage limitation, not a WordPress password problem and not an MCP endpoint problem.

Update Codex and retry because this behavior may improve in newer builds. If it remains, do not work around it by copying OAuth tokens into prompts, shell history, or ordinary files. Use a supported desktop Codex environment for the authenticated WordPress action while continuing to research and draft in Termux.

The server is configured but no tools appear. Start a fresh Codex process after configuration, run codex mcp list, and use /mcp inside the Codex terminal UI to inspect active servers. Run codex mcp --help when the installed CLI syntax is uncertain.

The account connects, but a particular site cannot be managed. Enumerate the sites first. In this session, the same account returned a usable WordPress.com site with partial MCP support, another site requiring a paid plan, and several disconnected Jetpack sites. Authentication alone does not guarantee that every site exposes tools.

5  ·  Ask Codex to Consult Official OpenAI Documentation

When CLI behavior may have changed, prompt Codex to consult the current official documentation instead of relying only on model memory. Name the source, the error, the evidence you want inspected, and the boundary that no configuration should be changed without approval.

The official references for this workflow are the Codex manual and its MCP configuration documentation.

GoalExample Prompt
Verify setup“Use current official OpenAI Codex documentation to verify how a Streamable HTTP MCP server and OAuth login should be configured. Cite the exact OpenAI pages you used. Then inspect my wpcom-mcp registration without changing it.”
Debug 404“Debug this Codex MCP initialization error: HTTP 404. First inspect codex mcp get wpcom-mcp; compare the transport and URL with current official OpenAI MCP documentation and the service’s official endpoint. Explain the cause before making changes.”
Debug OAuth“The browser says OAuth succeeded, but a fresh Codex session reports AuthRequired. Use official OpenAI Codex documentation, check codex mcp list and /mcp, distinguish server reachability from credential persistence, and do not ask me to paste a token.”
Collect evidence“Diagnose this connection layer by layer: saved configuration, endpoint, transport, OAuth callback, stored credential, fresh-session discovery, WordPress site access, and tool permissions. Show the evidence for each conclusion.”

A useful troubleshooting prompt includes four things: the desired outcome, the observed error text, the authoritative sources to consult, and what Codex must not change without confirmation.

6  ·  Verify the Site Before Creating or Editing Content

Once the connector is working, ask Codex to list the accessible WordPress.com sites before writing anything:

Use the WordPress.com MCP tools to list the sites I can access.
Show each site ID, domain, connection status, and MCP availability.
Do not create or update content.

This session demonstrated why that step matters. The account had multiple sites, but only the intended Techucation site could perform the requested basic content operation. Use the numeric site ID or exact domain in later prompts, especially when similarly named or disconnected sites are present.

7  ·  Use a Draft-First Workflow

Tell Codex the target site and status explicitly:

Create a new post on malcolmlow.com as a draft.
Do not publish it.
Return the post ID, edit URL, and preview URL.

Before updating an existing draft, have Codex list recent drafts with their IDs and modification times. “The draft article” can be ambiguous when a site contains many drafts. In this session, the newest modified draft was identified as post 3955 before any write operation was attempted.

Publishing and editing are separate actions. A request to improve formatting should preserve status: draft. A request to publish should identify the site and post ID, and Codex should state that the change will make the article public before executing it.

8  ·  Security and Review Checklist
  • Install Termux and Codex only from trusted sources.
  • Never place WordPress passwords, OAuth tokens, or credential files in prompts.
  • Keep ~/.codex private.
  • Enable only the WordPress MCP tools you need.
  • Confirm the exact domain and post ID before a write.
  • Keep new and revised articles as drafts until reviewed.
  • Check headings, code blocks, links, categories, tags, featured image, alt text, and mobile layout.
  • Revoke WordPress.com access if the phone is lost or replaced.
  • Use Android screen locking and device encryption.
9  ·  Command Cheat Sheet
# Prepare Termux
pkg update
pkg upgrade
pkg install nodejs git

# Install Codex
npm install -g @openai/codex
codex --version

# Register WordPress.com MCP
codex mcp add wpcom-mcp --url https://public-api.wordpress.com/wpcom/v2/mcp/v1

# Authenticate and inspect
codex mcp login wpcom-mcp
codex mcp get wpcom-mcp
codex mcp list
codex mcp --help

# Start a fresh session
codex

# Inside the Codex TUI
/mcp

Once the connection works, keep the workflow conservative: let Codex research and draft first, create or update the WordPress draft second, review it in the editor, and publish only after the exact site and post have been confirmed.

AI Workflows · 2026

✦ This article was assembled with the assistance of OpenAI Codex and checked against current official Codex documentation ✦

How to Connect Claude to the dev.to API and Build a Reusable Skill

AI WORKFLOWS · 2026
Connecting Claude to an API with no MCP connector, and building a reusable skill from it.

MCP (Model Context Protocol) connectors extend Claude’s reach into external services, but connector coverage is uneven across platforms. dev.to is one such gap: no MCP connector currently supports writing to it. This post documents the workaround — calling dev.to’s REST API directly, converting that workflow into a reusable Claude skill, and the reasoning behind keeping the API key out of that skill entirely.


1  ·  The Gap: No MCP Connector for dev.to Writes

Claude connects to external services through MCP (Model Context Protocol) connectors — Gmail, Google Drive, Shopify, and so on. A community-built dev-to-mcp server exists, but it only wraps dev.to’s public API: get_articles, get_article, get_user, get_tags, get_comments, search_articles. Read-only, by design — the author explicitly left out the authenticated write endpoints to keep the initial release simple.

The existence of an MCP server for a service doesn’t mean everything that service’s API can do is exposed through it. That distinction matters when planning any AI-agent integration against a third-party platform.

2  ·  The Workaround: dev.to’s Real REST API

dev.to has had a full authenticated REST API for years — create, read, update, delete articles, plus follower and notification endpoints. It’s a plain API, not an MCP tool, which means using it requires a general-purpose way to make HTTP calls: a sandboxed environment with network access and a shell. The complete reference — every endpoint, required headers, and response schema — is published at developers.forem.com/api/v1. This is the page an AI agent (or a person) should read directly before writing any integration code against it, rather than relying on prior training knowledge of the API shape.

The workflow reduces to three plain HTTP calls:

1. GET  /api/articles/:username/:slug   → find the numeric article ID
2. GET /api/articles/:username/:slug → pull body_markdown to edit locally
3. PUT /api/articles/:id (with api-key header) → push the new title, tags, body

The raw markdown is fetched, edited with standard text-replacement, and pushed back with a signed request. The published URL and slug remain unchanged after a title edit, so existing links continue to resolve correctly.

3  ·  Turning It Into a Reusable Skill

Claude supports “skills” — markdown files that document a workflow so it doesn’t need to rediscover the same steps in a future session. The dev.to workflow above was written up as a SKILL.md covering the exact curl patterns, a link to the official API reference, the tag-format constraints (max four tags, alphanumeric only), and the note that a PUT only changes the fields explicitly sent.

That file sits alongside similar skills built for a Shopify cross-listing workflow and a WordPress publishing workflow — each one converting a one-off problem-solving session into something reusable, rather than re-explaining the same constraints each time.

🔐 The rule that mattered more than any of the code: the API key never went into the skill file.

Skill files persist. They are read back into context automatically in every future conversation, on any device, indefinitely. A live credential sitting in one is a standing liability — no expiry, no encryption, no audit trail, and no way to verify later who or what might have accessed it. The skill therefore documents where to obtain the key and includes a reminder to request it fresh each session, but the value itself is never written down. It is used for the curl calls in a single conversation, then discarded.

The key is generated at dev.to → Settings → Extensions, under the “DEV API Keys” section near the bottom of that page.

4  ·  Applying This Pattern Elsewhere

This pattern is not dev.to-specific. It applies to any service where an MCP connector doesn’t yet exist, or only covers part of the API:

  • Check whether the service has a plain REST API, even without an MCP wrapper — most established platforms do.
  • Have Claude write the skill file after the problem has been solved once, so it captures the real constraints (rate limits, required headers, field-naming quirks) rather than a guess.
  • Keep secrets out of anything durable. If a workflow needs a credential, the skill should describe how to obtain one and where to provide it — never store the value itself.
  • State the no-storage requirement explicitly when asking for a skill to be created, since the entire purpose of a skill is to outlive the conversation.
5  ·  Example Prompts for Each Step

The steps above map directly onto plain-language requests. These are the actual prompts that drive each stage of the workflow:

Step Example Prompt
Check what’s possible “Check your connectors and skills — can you update a post on dev.to?”
Set up (first time) “Look up the API docs at developers.forem.com/api/v1, figure out how to update a dev.to article, then store what you learn into a skill — don’t save the API key in it.”
Connect (each session) “Use the dev.to skill to update this post: [url]” — Claude should then ask for the API key and remind you it’s generated at dev.to → Settings → Extensions.
Look up an article “Look up this dev.to article and tell me its current title, tags, and ID: [url]”
Create a new post “Publish a new dev.to post titled ‘[title]’ with this content: [markdown], tagged [tag1, tag2, tag3].”
Update an existing post “Update my dev.to post at [url] — change the title to ‘[new title]’ and add the tag [tag].”
Sync with a source article “This dev.to post is a cross-post of . Update it to match the current version.”

Each prompt is a plain description of the desired outcome, not a set of technical instructions — the skill file supplies the mechanics (endpoints, headers, field constraints) so the request itself can stay short.


AI Workflows · 2026

✦ This article was assembled with the assistance of Claude by Anthropic

Quantum Computing: A Complete Learning Path

QUANTUM SERIES 2026
The complete learning path, from a single qubit to Grover’s algorithm.

This is the index to the Techucation Quantum Series: a sequence of hands-on posts that build quantum computing from the ground up. Each one stands on its own, but together they form a single arc, from what a qubit actually is, through the rules that make quantum mechanics strange, to the algorithms that turn those rules into a real speedup. The order below is a learning path from first principles to algorithms, not the order the posts were written.

New to the topic? Read top to bottom. Already comfortable with qubits and gates? Skip ahead to the algorithms in Section 4.

Foundational Pre-reading: The Math Behind the Phase
0
Euler’s Formula: Why e Is Just Shorthand for a Circle
Optional warm-up before the qubit posts: the complex plane, i as a 90° rotation, and why the phase factor e traces a circle.
1  ·  Start Here: Qubits and Superposition
1
Quantum Computing From First Principles: Qubits, Hadamard Gates & Why H² = I
First principles: what a qubit is, how the Hadamard gate builds superposition, and why tensor products scale the state space.
2  ·  The Hadamard Toolkit
2
The Quantum Fourier Transform of a Single Qubit is the Hadamard Transform
The one-qubit QFT turns out to be exactly the Hadamard gate, a small result that anchors the bigger picture.
3
The Walsh-Hadamard Matrix: Backbone of Grover’s Diffusion Operator
How the Hadamard sign table generalises to n qubits and powers Grover’s diffusion step.
3  ·  The Rules of the Quantum World
4
Reversible Computation in Quantum Computing
Why every quantum gate must be reversible, and how ancilla bits turn irreversible logic into unitary logic.
5
The Cost of Garbage in Quantum Computing
Leftover junk qubits destroy interference; uncomputation cleans them up to protect the speedup.
6
The No-Cloning Theorem: Why You Cannot Copy a Qubit
A short proof that an unknown quantum state cannot be duplicated, and what that impossibility makes possible.
7
Quantum Teleportation, and Why It Is Not Cloning
Moving an unknown qubit from one place to another without ever copying it, using entanglement and two classical bits.
4  ·  Algorithms
8
Understanding Phase Kickback
The mechanism where the target qubit flips the control’s phase, the trick underneath Deutsch’s, Grover’s, and Shor’s.
9
Deutsch’s Algorithm: The Four Cases
The four one-bit Boolean functions, the reversible oracle, and the single query that beats the classical two.
10
Deutsch Revisited: Quantum vs Classical in Qiskit
The same algorithm in running Qiskit code: two classical queries against one quantum query.
11
Grover’s Algorithm: Inversion About the Mean
A full three-qubit walkthrough of the oracle and the amplitude amplification that surfaces the marked item.
5  ·  Entanglement and Bell’s Inequality
12
The CHSH Game Simulator and Bell’s Inequality
An interactive game where quantum entanglement beats the classical 75 percent ceiling and violates Bell’s inequality.

Quantum Series 2026  ·  Built with Qiskit 1.x

✦ This article was generated with the assistance of Claude by Anthropic

Quantum Teleportation in Quantum Computing, and Why It Isn’t Cloning

QUANTUM SERIES 2026
Moving a qubit you are forbidden to copy.

Teleportation is the most over-sold word in quantum computing. It conjures Star Trek transporters and faster-than-light messaging, and almost every popular account quietly implies you end up with a copy of the original. You do not. Quantum teleportation moves an unknown quantum state from one qubit to another while destroying the original, and that destruction is not an incidental detail. It is the mechanism that keeps the protocol on the right side of the no-cloning theorem.


1  ·  A quick word on no-cloning

This whole protocol is haunted by the no-cloning theorem: there is no operation that copies an arbitrary unknown quantum state. That proof and its consequences are covered in a recent post, The No-Cloning Theorem in Quantum Computing: Why You Can’t Copy a Qubit, and are not re-derived here.

The single fact needed going forward: you cannot deterministically duplicate an unknown qubit. The qualifiers matter, because teleportation lives in the gaps between them. The theorem forbids copying unknown states (a known state you can re-prepare at will), it forbids deterministic, perfect copies, and it is a statement about unitary operations — and measurement, which teleportation leans on at the decisive moment, is not unitary.

2  ·  Why teleportation is not cloning

Here is the distinction in one sentence: cloning would leave |ψ⟩ in two places; teleportation leaves it in exactly one.

Partway through the protocol, Alice’s message qubit is measured. Measurement collapses it into a classical basis state — a plain |0⟩ or |1⟩ carrying none of the original amplitudes. By the time Bob’s qubit holds |ψ⟩, Alice’s qubit demonstrably does not. The state was relocated, and the accounting is exact: one copy in, one copy out. No moment ever exists where two qubits both carry |ψ⟩, so there is nothing for the no-cloning theorem to object to.

This also kills the faster-than-light fantasy. The protocol forces Alice to send Bob two ordinary classical bits. Until they arrive, Bob’s qubit is information-free, as the algebra below shows.

3  ·  The complete circuit

Here is the whole protocol in a single circuit. Read it left to right; the amber dashed dividers mark the three stages. The message qubit q0 starts in the unknown state |ψ⟩, while q1 and q2 both start in |0⟩.

1. Bell pair2. Alice measures3. Bob corrects
q0:HM
q1:H+M
q2:+XZ

Stage 1 — Bell pair. Alice and Bob share an entangled pair: an H on q1 followed by a CNOT from q1 onto q2 prepares (|00⟩ + |11⟩)/√2 across the two halves.

Stage 2 — Alice measures. Alice folds her message into the pair (a CNOT from q0 onto q1, then an H on q0) and measures both of her qubits, collapsing them to two classical bits.

Stage 3 — Bob corrects. Depending on those two bits, Bob applies an X and/or a Z to q2 — the X controlled by Alice’s q1 bit, the Z by her q0 bit — and q2 emerges as |ψ⟩. The next section is the algebra that fixes exactly which correction each outcome needs.

4  ·  The protocol in bra-ket and tensor form

Now the algebra behind that circuit. Three qubits: q0 carries |ψ⟩ = α|0⟩ + β|1⟩ (Alice), q1 is Alice’s half of the Bell pair, and q2 is Bob’s half. They pre-share |Φ+⟩ = (|00⟩ + |11⟩)/√2 on q1 q2.

Step 1 — the starting state. Tensor the message against the Bell pair:

|ψ⟩ = α|0⟩ + β|1⟩            (the unknown message on q0)

|ψ⟩ ⊗ |Φ+⟩ = (α|0⟩ + β|1⟩) ⊗ (|00⟩ + |11⟩)/√2
           = (1/√2) [ α|000⟩ + α|011⟩ + β|100⟩ + β|111⟩ ]

Step 2 — Alice’s CNOT (control q0, target q1):

CNOT (control q0, target q1)  flips q1 wherever q0 = 1:

= (1/√2) [ α|000⟩ + α|011⟩ + β|110⟩ + β|101⟩ ]

Step 3 — Alice’s Hadamard on q0. Substitute |0⟩ → (|0⟩+|1⟩)/√2 and |1⟩ → (|0⟩−|1⟩)/√2, then collect by the value of (q0 q1):

H on q0, then collect by the pair Alice will measure (q0 q1):

= (1/2) [ |00⟩ (α|0⟩ + β|1⟩)    ← case A
        + |01⟩ (α|1⟩ + β|0⟩)    ← case B
        + |10⟩ (α|0⟩ − β|1⟩)    ← case C
        + |11⟩ (α|1⟩ − β|0⟩) ]  ← case D

Each bracketed q2 state is the original |ψ⟩ acted on by a known Pauli. Alice measures, gets one of four outcomes (each with probability 1/4), sends the two bits to Bob, and Bob undoes the Pauli. The Case column ties each row back to the matching line in Step 3:

Case
Alice measures (q0 q1)
Bob holds on q2
Relation to |ψ⟩
Bob applies
A
00
α|0⟩ + β|1⟩
I |ψ⟩
nothing
B
01
α|1⟩ + β|0⟩
X |ψ⟩
X
C
10
α|0⟩ − β|1⟩
Z |ψ⟩
Z
D
11
α|1⟩ − β|0⟩
ZX |ψ⟩
X then Z

Bob applies Zm0 Xm1 — an X if m1 = 1, then a Z if m0 = 1 — and every branch lands back on α|0⟩ + β|1⟩ = |ψ⟩.

5  ·  Qiskit — classical feed-forward

This version measures mid-circuit and uses real classical conditioning via if_test, the honest picture of the protocol. The verification trick: rather than read out Bob’s state, apply the inverse of the preparation to q2. If teleportation worked, that must collapse q2 to |0⟩ on every shot.

import numpy as np
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile
from qiskit.circuit.library import StatePreparation
from qiskit.quantum_info import random_statevector
from qiskit_aer import AerSimulator

# Unknown state to teleport (StatePreparation is unitary -> invertible)
psi  = random_statevector(2)
prep = StatePreparation(psi)

q   = QuantumRegister(3, “q”)     # q0 message, q1 Alice, q2 Bob
mz  = ClassicalRegister(1, “mz”)  # q0 result -> drives Z
mx  = ClassicalRegister(1, “mx”)  # q1 result -> drives X
out = ClassicalRegister(1, “out”) # verification bit
qc  = QuantumCircuit(q, mz, mx, out)

qc.append(prep, [0]); qc.barrier()        # 1. load |ψ⟩ onto q0
qc.h(1); qc.cx(1, 2); qc.barrier()        # 2. Bell pair on (q1,q2)
qc.cx(0, 1); qc.h(0)                      # 3. Alice’s basis change
qc.measure(0, mz); qc.measure(1, mx); qc.barrier()

with qc.if_test((mx, 1)):                 # 4. Bob’s corrections
    qc.x(2)
with qc.if_test((mz, 1)):
    qc.z(2)
qc.barrier()

qc.append(prep.inverse(), [2])            # 5. un-prepare on Bob: must read 0
qc.measure(2, out)

counts = AerSimulator().run(transpile(qc, AerSimulator()), shots=4000).result().get_counts()
clean  = all(k.split()[0] == “0” for k in counts)   # leftmost bit = out
print(counts); print(“Teleportation verified:”, clean)
The out bit comes back 0 on 100% of shots regardless of the random (mx, mz) branch — exactly the claim that Bob reconstructs |ψ⟩ in every case.

6  ·  No faster-than-light, and the takeaway

Before Bob learns (m0, m1), his qubit is an equal mixture of the four branch states. Averaging the four projectors gives the Pauli twirl:

ρ_Bob = (1/4)( |ψ⟩⟨ψ| + X|ψ⟩⟨ψ|X
              + Z|ψ⟩⟨ψ|Z + XZ|ψ⟩⟨ψ|ZX )  =  I/2   for every |ψ⟩

for any |ψ⟩. Bob’s local state is identical no matter what Alice sent, so no information has reached him yet. The classical bits are not a formality — they are the only thing that carries the state across, and they travel no faster than light.

Takeaway. No-cloning forbids duplicating an unknown qubit (proof here). Teleportation never attempts a copy: it entangles the message with a shared Bell pair, measures the original out of existence, and ships two classical bits naming which of four Pauli corrections rebuilds the state on the other end. Exactly one copy before, exactly one after. No-cloning is not a bug the protocol works around — it is the reason the protocol has to look the way it does.

Quantum Series 2026  ·  Built with Qiskit 1.x

✦ This article was generated with the assistance of Claude by Anthropic

Move Your WordPress.com Domain to Cloudflare and Halve the Renewal

TECHUCATION  ·  DOMAINS 2026
Moving a WordPress.com domain to Cloudflare Registrar, and what it actually costs.

My WordPress.com domain renewal notice came in at £16/year, with auto-renew switched off and the expiry only a couple of days away. That is a fine price for convenience, but the same name sits on Cloudflare Registrar at wholesale cost with no markup. This post walks through the move end to end, including the one step that quietly breaks things if you rush it, and lays out the real cost difference.

The short version: you do not “renew at Cloudflare”. You transfer the domain to Cloudflare, which extends the registration by a year in the process. The saving is real, but the order of operations matters.


1  ·  The cost case

Cloudflare Registrar charges exactly what the registry charges them, with zero markup, and bundles WHOIS privacy for free. Retail registrars add a margin on top. For a .net the difference looks like this:

Item WordPress.com Cloudflare Registrar
.net renewal (1 yr) £16 (approx US$20) approx US$10.44 (at cost)
Markup Retail margin None (wholesale pass-through)
WHOIS privacy Included Included, free
Approx 5-year cost approx US$100 approx US$52
Figures are indicative for mid-2026. Because Cloudflare is at cost, your renewal tracks the registry wholesale rate, so it moves up if the registry (Verisign for .net) raises prices. The trade-off: Cloudflare requires the domain to run on Cloudflare DNS.
2  ·  The gotcha: transfer, not renew, and DNS moves first

Two things trip people up:

You cannot renew a domain at a registrar where it is not registered. To get Cloudflare pricing you transfer the domain in. A gTLD transfer (.com, .net, .org) automatically adds one year, so it replaces the renewal rather than stacking on top of it.

Cloudflare will not let you transfer the registration until the domain is already running on Cloudflare DNS. So the real sequence is DNS first, registrar second, with any redirect rebuilt in the middle so the site never goes dark.

Mind the expiry window. Do not start this within a few days of expiry and then walk away. A transfer left to auto-complete can take up to 5 days. If you are close to the date, expedite it (see step 6) rather than waiting out the clock.
3  ·  Step by step

The full order of operations:

1   Unlock the domain at WordPress.com, get the EPP / auth code
2   Add the domain as a Free zone in Cloudflare
3   Stage the redirect in Cloudflare (before flipping nameservers)
4   Change nameservers at WordPress.com to Cloudflare’s pair
5   Wait for the Cloudflare zone to go Active
6   Initiate the transfer in Cloudflare, paste the EPP code, pay
7   Approve / expedite the transfer on the WordPress.com side
8   Verify: registrar, new expiry, redirect, DNSSEC

Step 1. In WordPress.com under Upgrades > Domains, open the domain, turn off Transfer lock, then start the transfer-out flow far enough to reveal the EPP / auth code. Copy it. Do not let WordPress walk you all the way through its own wizard, you only want the code.

Step 2. In the Cloudflare dashboard, Add a domain, choose the Free plan. Cloudflare scans existing DNS and assigns you two nameservers like name.ns.cloudflare.com. Note them.

Step 3. If the domain is a redirect (common when it just points at another site of yours), rebuild that redirect in Cloudflare now while it sits idle. See section 4.

Step 4. Back at WordPress.com, switch the nameservers from WordPress to the two Cloudflare nameservers.

Step 5. Cloudflare flips the zone to Active once it sees the nameserver change, usually under an hour. The transfer option stays greyed out until then.

Step 6. Once Active, go to Domain Registration > Transfer Domains, select the domain, paste the EPP code, and pay the at-cost fee. This payment includes the added year.

Step 7. Watch for the confirmation from the losing registrar. WordPress.com surfaces a Transfer Management page with an Accept Transfer button. Clicking it skips the 5-day wait and completes the transfer in minutes.

Done. The registry should now show the registrar as Cloudflare, status Active, and the expiry rolled forward by a year.
4  ·  The redirect-only trap

If your domain only exists to redirect to another site, the imported records (the host’s A records and a couple of CNAMEs) become redundant once you build a Cloudflare Redirect Rule. Tempting to delete them all for a tidy zone. Here is the trap:

A Cloudflare Redirect Rule only fires on traffic that reaches Cloudflare’s edge. Traffic only reaches the edge if the hostname resolves to a proxied record (orange cloud). Delete every record and the name resolves to nothing, so the redirect goes dark.

The fix is to keep one proxied placeholder for the rule to attach to:

Type Name Value Proxy
A @ 192.0.2.1 Proxied
CNAME www @ Proxied (only if you want www)
TXT @ “google-site-verification=…” DNS only

192.0.2.1 is a reserved TEST-NET address that never routes anywhere, which is exactly what you want: the proxy intercepts the request before that IP is ever used. Then a single Redirect Rule (Rules > Redirect Rules) handles the rest:

Field Setting
When (match) hostname ends with example.net
Then (action) 301 to https://example.com + path
Preserve query string On

Keep the TXT verification record as DNS only. It does not need to resolve to anything, it just needs to exist.

5  ·  After the transfer

Three things to settle once the registrar shows Cloudflare:

Auto-renew. Optional, but turning it on (Domain Registration > your domain) means you never repeat the two-days-from-expiry scramble. If you leave it off, set yourself a reminder a few weeks before the date.

DNSSEC. Worth enabling for the added integrity protection. Because Cloudflare is now both your DNS and your registrar, the DS record is published to the registry automatically, so it activates without you touching the registrar by hand. Give it from a few minutes up to a couple of hours to show as signed at the registry.

Registrar lock. On by default at Cloudflare, so that one is already handled.

One caution with DNSSEC: once the DS record is published, do not move nameservers away from Cloudflare or disable DNSSEC out of order. Breaking the signature chain is the classic way to make a domain go dark, because validating resolvers will reject it. As long as DNS stays on Cloudflare, you are fine.

Net result: same domain, half the renewal cost, a year added, and the registrar consolidated with your DNS. The only part that needs care is the DNS-first ordering and not over-deleting the redirect records. Everything else is a few clicks and a short wait.


Techucation 2026  ·  Domains & DevOps  ·  Cloudflare Registrar + WordPress.com

✦ This article was generated with the assistance of Claude by Anthropic

The No-Cloning Theorem in Quantum Computing: Why You Can’t Copy a Qubit

QUANTUM SERIES 2026
The no-cloning theorem: why an unknown quantum state cannot be copied, and what that buys us.

Copying is so ordinary in classical computing that we never think about it. Every assignment, every memory write, every Ctrl+C duplicates a bit string perfectly and at will. Quantum mechanics flatly refuses to do the same for an unknown state. There is no machine, no clever circuit, no sequence of gates that takes an arbitrary qubit and hands you back two identical copies of it. This is the no-cloning theorem, and far from being a limitation we tolerate, it is the structural reason quantum key distribution is secure, the reason entanglement cannot be used to signal faster than light, and the reason quantum error correction had to be reinvented from scratch.

The proof is short. It falls out of two properties we have already relied on throughout this series: linearity of quantum evolution, and unitarity. Below we prove it both ways, clear up the very common confusion about CNOT “copying” a qubit, walk through the consequences, and then watch a cloning attempt fail in Qiskit.


1  ·  What “cloning” would actually mean

A cloning machine would be a single fixed unitary U together with a standard blank register |e⟩, such that for every possible input state |ψ⟩ it produces:

U  ( |ψ⟩ ⊗ |e⟩ )  =  |ψ⟩ ⊗ |ψ⟩

Three pieces of that statement deserve unpacking, because the whole theorem turns on them.

What |e⟩ is, and what “blank” means. The register |e⟩ is simply the second slot, the one that will end up holding the copy. We call it “blank” by analogy with an empty sheet of paper or an uninitialised memory cell: before the operation it carries no information whatsoever about the input |ψ⟩. The conventional choice is |0⟩, or |0…0⟩ when the copy needs several qubits, but |e⟩ does not have to be the zero vector specifically. Any fixed pure state works equally well for the theorem. The property that actually matters is not its literal value but that it is independent of the unknown input. A register that already secretly equalled |ψ⟩ would not be blank, and you would not have copied anything, you would have been handed the answer.

What “fixed” means, for both U and |e⟩. Fixed means chosen in advance and identical on every run, never allowed to depend on which |ψ⟩ happens to come in. This is the condition that keeps the problem honest. If you were permitted to pick |e⟩ or U based on the input, you would first have to know what |ψ⟩ is, and at that point there is nothing left to clone: you could just prepare a second copy yourself. So the cloner gets one unitary and one starting register, and they must work for an arbitrary, unknown input. The claim of the theorem is that no such pair (U, |e⟩) exists.

Why cloning a known state is allowed, and how you do it. The theorem forbids copying an unknown arbitrary state. It says nothing about states you already understand, and there are two everyday ways such a state can be “known”:

You know… How you get two copies
The preparation recipe (the amplitudes, or the circuit that builds it) Just run the preparation twice on two fresh |0⟩ qubits. You are re-preparing from a known description, not copying an unknown state.
That the state is one of a known orthogonal set Measure in the basis that distinguishes the set. Orthogonal states are eigenstates of that measurement, so they survive it undisturbed. Read off the label, then re-prepare as many copies as you like.

As a concrete example of the first route, if you are told the state is |ψ⟩ = Ry(θ)|0⟩ for a known angle θ, you simply apply Ry(θ) to two separate qubits. No universal device is involved, and no rule is broken. The contradiction in the next two sections appears only when no such side information exists, that is, when the same machine must handle a continuum of unknown inputs at once.

The one-line distinction: you can always re-prepare a state you know how to build, and you can copy states that act like classical labels. What you cannot do is build one fixed machine that duplicates an arbitrary, unknown state handed to you blind.

2  ·  Proof I: linearity forbids it

Assume, for contradiction, that a universal cloner U exists. Pick two arbitrary states |ψ⟩ and |φ⟩. By assumption U clones both of them:

U |ψ⟩|e⟩  =  |ψ⟩|ψ⟩
U |φ⟩|e⟩  =  |φ⟩|φ⟩

Now feed the machine a superposition of the two inputs, |χ⟩ = (1/√2)(|ψ⟩ + |φ⟩). Quantum evolution is linear, so U acts term by term on the input:

U |χ⟩|e⟩  =  (1/√2) ( U|ψ⟩|e⟩  +  U|φ⟩|e⟩ )
         =  (1/√2) ( |ψ⟩|ψ⟩  +  |φ⟩|φ⟩ )

But if U is genuinely a cloner, then by definition it must also clone |χ⟩ itself, producing |χ⟩|χ⟩. Expanding that out:

|χ⟩|χ⟩  =  (1/2) ( |ψ⟩ + |φ⟩ )( |ψ⟩ + |φ⟩ )
      =  (1/2) ( |ψ⟩|ψ⟩ + |ψ⟩|φ⟩ + |φ⟩|ψ⟩ + |φ⟩|φ⟩ )

The two results disagree. Linearity gave us only the “diagonal” terms |ψ⟩|ψ⟩ and |φ⟩|φ⟩, whereas true cloning of |χ⟩ demands the cross terms |ψ⟩|φ⟩ and |φ⟩|ψ⟩ as well. They can only match if the cross terms vanish, which happens precisely when |ψ⟩ and |φ⟩ are identical or orthogonal. For general, non-orthogonal states the equality is impossible. The cloner cannot exist.

The contradiction is the same one that powers most quantum no-go results: a device defined by its action on a basis is forced, by linearity, into a behaviour on superpositions that contradicts the original specification.

3  ·  Proof II: unitarity forbids it

The linearity argument shows cloning fails for superpositions. A second proof, often considered the cleaner one, uses the fact that unitary operations preserve inner products. Suppose again that U clones two states:

U |ψ⟩|e⟩  =  |ψ⟩|ψ⟩
U |φ⟩|e⟩  =  |φ⟩|φ⟩

The inner product is taken over the full two-register states that U acts on, not over |ψ⟩ and |φ⟩ on their own. Label the two inputs and their images under U:

Input A   = |ψ⟩|e⟩        Output UA  = |ψ⟩|ψ⟩
Input B   = |φ⟩|e⟩        Output UB  = |φ⟩|φ⟩

If U is unitary, then   ⟨A|B⟩  =  ⟨UA|UB⟩

That identity, ⟨A|B⟩ = ⟨UA|UB⟩, is the definition of a unitary: it preserves inner products. U never acts on the inner product itself, which is only a number; it acts on the states, and unitarity says doing so cannot change their overlap. Now evaluate both sides, using the tensor-product factorisation ⟨a|⟨b| · |c⟩|d⟩ = ⟨a|c⟩ ⟨b|d⟩ and ⟨e|e⟩ = 1:

⟨A|B⟩   = ⟨ψ|⟨e| · |φ⟩|e⟩  =  ⟨ψ|φ⟩ ⟨e|e⟩  =  ⟨ψ|φ⟩
⟨UA|UB⟩ = ⟨ψ|⟨ψ| · |φ⟩|φ⟩  =  ⟨ψ|φ⟩ ⟨ψ|φ⟩  =  ⟨ψ|φ⟩²

so   ⟨ψ|φ⟩  =  ⟨ψ|φ⟩²

Write x = ⟨ψ|φ⟩. The condition x = x² rearranges to x(x − 1) = 0, whose only solutions are x = 0 or x = 1. In other words, cloning is consistent only when the two states are orthogonal (x = 0) or identical (x = 1). Any pair of distinct, non-orthogonal states, the generic case, breaks the equality. No universal cloner can exist.

⟨ψ|φ⟩ Relationship Cloneable?
0 Orthogonal (a known basis set) Yes, this is just classical copying
1 Identical (already known) Yes, trivially
anything else Distinct, non-orthogonal No

Both proofs converge on the same boundary. Orthogonal states carry distinguishable classical labels and can be copied; overlapping quantum states cannot.

4  ·  “But doesn’t CNOT copy a qubit?”

This is the single most common point of confusion, and it is worth resolving carefully. A CNOT with the input qubit as control and a fresh |0⟩ as target looks exactly like a copy operation. On computational basis states it behaves like one:

CNOT |0⟩|0⟩  =  |0⟩|0⟩
CNOT |1⟩|0⟩  =  |1⟩|1⟩

So far it really is copying: the second qubit ends up matching the first. The trouble appears the moment the control is a superposition. Take |ψ⟩ = a|0⟩ + b|1⟩ as control and |0⟩ as target:

CNOT ( a|0⟩ + b|1⟩ )|0⟩  =  a|00⟩ + b|11⟩

Compare that with what a true clone would have produced, namely |ψ⟩|ψ⟩:

|ψ⟩|ψ⟩  =  a²|00⟩ + ab|01⟩ + ab|10⟩ + b²|11⟩

These are different states. The CNOT output a|00⟩ + b|11⟩ is an entangled pair, not two independent copies. If you discard the original and look at the “copy” on its own, you do not find |ψ⟩; you find a mixed state that has lost the phase relationship between a and b entirely. CNOT copies the value in the computational basis but destroys the superposition structure that made the state quantum in the first place. That is exactly the gap between copying classical information, which is always allowed, and cloning a quantum state, which is not.

Rule of thumb: CNOT copies basis labels, not quantum states. The instant the input is in superposition, the “copy” is entanglement, not duplication.

5  ·  Why this single theorem matters so much

No-cloning is not a footnote. Three of the most important results in quantum information rest directly on it.

Quantum key distribution. In BB84, Alice sends qubits encoded in randomly chosen bases. An eavesdropper, Eve, would love to intercept each qubit, keep a copy, and forward the original untouched so she can measure her copies later once the bases are announced. No-cloning makes that impossible. Eve cannot duplicate an unknown qubit, so she is forced to measure in transit, and measuring in the wrong basis disturbs the state and injects a detectable error rate. The security of the protocol is the no-cloning theorem wearing a different hat.

No faster-than-light signalling. Entanglement correlates distant measurement outcomes, which has always tempted people into superluminal-communication schemes. Many of those schemes secretly assume Bob can clone his half of an entangled pair, make many copies, and read off the statistics to learn which basis Alice measured in. No-cloning closes that loophole and is one of the reasons quantum mechanics and relativity coexist without paradox.

Quantum error correction. Classical error correction leans on the simplest trick imaginable: copy the bit several times and take a majority vote. That is illegal in the quantum setting, because you cannot copy an unknown logical state. Quantum codes had to be built on a different principle, spreading logical information across many physical qubits using entanglement and measuring error syndromes without ever reading or duplicating the encoded state. The whole architecture of fault tolerance is shaped by the fact that the obvious classical fix is off the table.

A useful way to hold it in your head: no-cloning is what stops quantum information from behaving like classical information. Almost everything that makes quantum protocols both powerful and secure traces back to that one restriction.

6  ·  Watching a clone fail in Qiskit

The abstract proof is convincing, but it is satisfying to watch the failure happen numerically. We attempt the naive CNOT “clone” of the state |+⟩ = H|0⟩, then measure how badly it falls short by two yardsticks: fidelity against the intended |+⟩|+⟩, and the purity of the copy qubit on its own.

Three terms in plain language:

Fidelity is a similarity score between two quantum states, from 0 to 1. Think of it as a match percentage: 1.0 means identical, 0 means completely unrelated.

Reduced state is the honest description of one qubit when you ignore its partner. Picture two coins glued so they always land the same way: cover one and look at just the other, and that single coin looks like a plain 50/50 flip. The “match” information lived in the pair, not in either coin alone. Discarding the partner mathematically is called tracing it out.

Purity tells you whether a state is sharp and definite or a blurry random mixture. Purity 1 is a clean, definite state. For a single qubit the lowest value is 0.5, called maximally mixed, which is total randomness, the quantum version of a fair coin holding no information.

from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector, partial_trace, state_fidelity

qc = QuantumCircuit(2)
qc.h(0)         # prepare |+> on qubit 0 (the “original”)
qc.cx(0, 1)    # naive “cloning” attempt via CNOT

state = Statevector(qc)
print(state)   # (|00> + |11>)/sqrt(2), a Bell state

target = Statevector.from_label(‘++’)   # what we wanted: |+>|+>
print(state_fidelity(state, target))   # 0.5

rho_copy = partial_trace(state, [0])   # trace out the original
print(rho_copy.data)   # I/2, maximally mixed
print(rho_copy.purity().real)   # 0.5

Running it gives:

Output state:  (√2/2)|00⟩ + (√2/2)|11⟩
Fidelity to |+⟩|+⟩:  0.5
Reduced state of copy:  [[0.5, 0], [0, 0.5]]
Purity of copy:  0.5

Every number tells the same story. The output is a maximally entangled Bell state, not the product |+⟩|+⟩ we were hoping for, and the fidelity to the intended clone is only 0.5. Trace out the original and the supposed “copy” is the maximally mixed state I/2, with purity 0.5 rather than 1. The copy retains no memory of the |+⟩ superposition at all; it is as good as a fair coin. The CNOT did precisely what the theorem says it must: it produced correlation, not duplication.

Try changing qc.h(0) to any other single-qubit rotation, say qc.ry(0.7, 0). The fidelity stays stubbornly below 1 for every non-basis input, which is the no-cloning theorem reproduced one statevector at a time.

Quantum Series 2026  ·  Built with Qiskit 1.x

✦ This article was generated with the assistance of Claude by Anthropic

About the author

Malcolm Low is an Associate Professor at the Singapore Institute of Technology, writing on quantum computing, programming, and applied computing from Singapore.

Website: malcolmlow.com  ·  Singapore

凤凰传奇《山河图》MV

音乐分享 · MUSIC
凤凰传奇《山河图》— 一幅泼墨写就的锦绣河山

《山河图》(Shānhé Tú) 是凤凰传奇于 2019 年发布的一首国风作品。曲风磅礴大气,以”山””河””图”三段层层铺陈,把万壑千岩、星奔川鹜的意象堆叠成一幅徐徐展开的水墨长卷,再以泼墨收束。玲花高亢的唱腔与曾毅的念白对仗,配上民族器乐与现代编曲的融合,是凤凰传奇近年颇具代表性的一首作品。

开篇一段便奠定了整首歌的水墨基调:

看这山 万壑千岩 连一川又一川
让这河 星奔川鹜 结一湾又一湾
谱这图 鸾回凤舞 重峦高不可攀
泼了墨 墨饱笔酣 润我锦绣河山
— 凤凰传奇《山河图》开篇
完整歌词请在正版平台查看: KKBOX · QQ音乐 · Spotify

✦ This post was assembled with the assistance of Claude by Anthropic

Publishing to WordPress with Claude and the WordPress MCP Connector

AI Productivity · Claude · WordPress MCP

Publishing to WordPress with Claude and the WordPress MCP Connector

A practical guide to using Claude on claude.ai to draft, style, and publish blog posts directly to your WordPress site — with hard-won lessons on what WordPress strips, and how to work around it.

Several posts on this blog — including Word Embeddings Explained, SingIDBot, and the OpenClaw Telegram integration guide — were written, styled, and published entirely through Claude on claude.ai, using the WordPress MCP connector. This post documents exactly how that workflow operates, what problems arise, and how to resolve them.

The combination of Claude’s HTML generation capability and the WordPress MCP connector creates a surprisingly smooth authoring pipeline, provided you know the constraints WordPress imposes on custom HTML blocks. Those constraints are the non-obvious part, and they are addressed in detail below.

Prefer Codex on Android? The companion guide, How to Connect Codex to WordPress.com and Post from Termux on Android, covers Codex CLI setup, MCP endpoint debugging, OAuth token-storage difficulties in Termux, and a draft-first workflow.

1. Prerequisites

Before you begin, the following need to be in place:

RequirementDetails
Claude account on claude.aiFree tier works; a Pro account gives longer contexts useful for large HTML posts.
WordPress.com siteThe MCP connector works with WordPress.com-hosted blogs. Self-hosted WordPress.org sites are not directly supported by the connector.
WordPress MCP connector enabledIn claude.ai, go to Settings → Integrations (or Connectors) and enable the WordPress.com connector. Authenticate with your WordPress.com account.

2. The Overall Workflow

The end-to-end process has three stages. Claude handles all of them in a single conversation.

Stage 1

Draft & Style

Provide Claude with your content and request a WordPress HTML block with inline CSS only. No <style> tags.

Stage 2

Review Output

Preview the rendered HTML in claude.ai artifacts. Request edits until the post looks correct.

Stage 3

Publish via MCP

Ask Claude to post using the WordPress connector. It checks categories and tags, creates any missing ones, then submits as a draft for your review.

The key prompt to kick off Stage 1:

“Generate a WordPress post using a custom HTML block with inline CSS only. Do not use <style> tags, <script> tags, or SVG.”

For Stage 3, once the HTML is finalised:

“Post this to malcolmlow.com using the WordPress connector. Use appropriate categories and tags. Post as a draft first.”

3. How the WordPress MCP Connector Works

The MCP (Model Context Protocol) connector gives Claude direct access to your WordPress.com REST API. When you ask Claude to post, it performs these operations internally:

  1. Loads the connector via an internal tool search, resolving the WordPress.com:wpcom-mcp-content-authoring tool.
  2. Lists existing categories using categories.list on your site to find IDs for any categories you want.
  3. Lists existing tags using tags.list to find or create the tags for the post.
  4. Creates missing categories or tags using categories.create / tags.create if they do not already exist on the site.
  5. Creates the post using posts.create, passing the HTML content, title, category IDs, tag IDs, and status (draft or publish).
  6. Returns the preview and edit URLs so you can open the draft in WordPress immediately.

The post content must be wrapped in a wp:html block comment:

<!– wp:html –>
  <div style=”…”>…post content…</div>
<!– /wp:html –>

4. Problems Encountered — and How They Were Solved

The workflow is productive but not without friction. Several issues emerged across multiple posts on this blog. Each is documented here with its root cause and fix.

Problem 1: WordPress strips <style> blocks entirely

What happened: Early posts used a <style> tag defining CSS classes. WordPress silently removed it on save, stripping all styling.

Fix: Every CSS rule must be written as an inline style="..." attribute. Claude handles this when instructed: “Use inline CSS only. Do not use <style> tags.”

Problem 2: WordPress strips SVG elements

What happened: Inline SVG circuit diagrams were stripped on save, leaving blank spaces.

Fix: Replace SVG with HTML-native layout (see Problems 6 and 7 for the full technique). Instruction: “Do not use SVG. Use CSS flexbox and inline-block spans for all diagrams.”

Problem 3: <script> tags are blocked

What happened: JavaScript interactivity was silently discarded by WordPress content sanitisation.

Fix: All interactivity must be replaced with pure HTML/CSS alternatives. Standing instruction: “No <script> tags.”

Problem 4: API parameter case sensitivity

What happened: Passing "order": "DESC" returned a validation error.

Fix: Always use lowercase: "order": "desc".

Problem 5: Duplicate categories and tags

What happened: Claude created duplicate taxonomy terms without checking first.

Fix: Always call categories.list and tags.list before any creation step.

Problem 6: Unicode box-drawing characters and &nbsp; spacing break alignment in WordPress

What happened: Unicode box-drawing characters inside <pre> elements and &nbsp; spacing in monospace divs looked correct in the claude.ai artifact but misaligned in WordPress — the theme’s font renders these characters at inconsistent widths.

Fix: Replace character-based layout with CSS layout:

  • Single-wire gates: display:flex; align-items:center rows with inline-block wire spans and bordered gate boxes.
  • Column vectors and matrices: display:flex container with border-left/border-right bracket spans and <br> for rows.

Instruction: “Never use &nbsp; for alignment or Unicode box-drawing characters. Use display:flex and inline-block spans instead.”

Problem 7: Multi-wire circuit diagrams with vertical connectors require position:absolute

What happened: The CNOT gate in the Phase Kickback post required a vertical line connecting a control dot (●) on one wire to an XOR circle (⊕) on another. Multiple approaches failed: border-bottom/border-top on adjacent table cells created horizontal bars instead of a vertical line; rowspan="2" in real <table> elements was visually correct but the WordPress theme’s CSS overrode <td> padding, creating unwanted row spacing that inline styles alone could not override.

Fix: A three-part solution:

  • Avoid theme td overrides: use <div style="display:table-cell"> instead of <td> — theme CSS targeting td selectors does not apply to divs.
  • Vertical connector: two separate display:flex; height:28px rows inside a position:relative; display:inline-block wrapper, with a position:absolute; width:2px connector div at a precisely calculated left value.
  • Asymmetric wire stubs: the control dot (12px wide) needs 21px wire stubs on each side; the XOR circle (20px wide) needs 17px stubs — these different widths keep both symbol centres at the same x-coordinate so the connector aligns with both. Wire stubs connect directly to the symbols with no padding gap between them.

Instruction: “For multi-wire circuits with vertical connections, use two flex rows in a position:relative wrapper with a position:absolute vertical connector. Wire stubs must touch each gate symbol directly with no padding gap.”

Tip: Let Claude Choose Categories and Tags Automatically

You do not need to specify categories and tags manually. Simply ask Claude to “use appropriate categories and tags” and it will inspect the existing taxonomy on your site, infer suitable terms from the post content, and create any new ones that are genuinely needed.

5. Step-by-Step: Posting via Claude and WordPress MCP

The following steps reproduce the exact workflow used to create and publish posts on this blog.

Step 1 — Enable the WordPress Connector in claude.ai

Go to claude.ai → Settings → Integrations. Find the WordPress.com connector and click Connect. Authorise it with your WordPress.com account.

Step 2 — Prepare your content and prompt Claude

Provide Claude with the raw content, a reference post URL, and the constraint set:

Generate a WordPress post as a custom HTML block.
Use inline CSS only — no <style> tags, no <script> tags, no SVG.
Never use &nbsp; for alignment or Unicode box-drawing characters.
Use display:flex and inline-block spans for diagrams and vectors.
For multi-wire circuits: use position:relative wrapper + position:absolute connector.
Match the styling of: [URL of a reference post]
Topic: [your content here]

Step 3 — Review the artifact in claude.ai

Review layout, colours, and diagram rendering. Verify no <style> or <script> tags appear. Check that circuit wires touch gate symbols directly.

Step 4 — Trigger the WordPress MCP posting

Post this to myhlow.wordpress.com using the WordPress connector.
Use appropriate categories and tags.
Status: draft

Claude will call categories.list and tags.list, create any missing terms, then execute posts.create and return the draft URLs.

Step 5 — Preview in WordPress and publish

Open the draft URL. If the Custom HTML block renders correctly, click Publish.

6. Installing the Workflow as a Reusable Skill

All the constraints from this guide are packaged as a downloadable Claude Skill. Once installed, the skill auto-loads every time you start a WordPress publishing task, so you never need to paste the prompt template manually again.

Step 1 — Enable Code Execution and File Creation

Go to Settings → Capabilities and toggle on Code Execution and File Creation. This is required for Claude to process the skill file when you upload it.

Step 2 — Open the Skills page

Navigate to https://claude.ai/customize/skills. Note: the Customize menu is only available in the browser version of Claude, not the mobile app. On mobile, use the direct link or enable Desktop site in your browser menu.

Step 3 — Upload the skill file

Click “+”“+ Create skill”“Upload a skill” → select wordpress-publish.skill → toggle it on.

Step 4 — Trigger in any new chat

In any new conversation, say “publish to WordPress” and Claude automatically loads all the constraints from this guide.

7. Quick Reference: Dos and Don’ts

DoDon’t
Use style="..." on every elementUse <style> blocks or CSS classes
Use display:flex + inline-block for single-wire gate diagrams and vectorsUse &nbsp; spacing or Unicode box-drawing characters for alignment
Use position:relative wrapper + position:absolute connector for multi-wire circuits; wire stubs touching symbols directlyUse border-top/border-bottom on table cells to simulate vertical connectors
Use <div style="display:table-cell"> to avoid WordPress theme td padding overridesRely on inline padding on actual <td> elements — theme CSS may override it
Wrap content in <!-- wp:html -->Use <svg> elements or <script> tags
Use lowercase "order": "desc" in API paramsUse uppercase "order": "DESC"
Post as draft first and preview in WordPressPublish directly without previewing the rendered block
Let Claude auto-select categories and tagsCreate taxonomy terms without checking for existing ones first
Set table header styles on <tr>, not <th>Apply background colours to <th> elements

Tip: Use a Reference Post to Anchor the Style

Giving Claude the URL of an existing post on your blog and asking it to match the styling is the fastest way to maintain visual consistency. The Word Embeddings post and the SingIDBot guide were both created this way, borrowing section card layout, banner colours, and code block styles from earlier posts in the series.

This article was generated with the assistance of Claude by Anthropic and posted via the WordPress MCP connector. ✨

Vibe Coding the Knight’s Tour with OpenAI Codex CLI

Vibe Coding with OpenAI Codex CLI

Vibe Coding the Knight’s Tour with OpenAI Codex CLI

A hands-on vibe coding session: scaffolding, solving, testing, and visualising the classic Knight’s Tour chess problem using OpenAI’s Codex CLI, guided entirely through natural language prompts rather than hand-written code.

“Vibe coding” — Andrej Karpathy’s term for building software by describing what you want in plain English and letting an AI agent write the code — has gone from a throwaway phrase to Collins Dictionary’s Word of the Year. This post is a real vibe coding session with OpenAI’s Codex CLI: no line of Python below was typed by hand. This post assumes you have Codex CLI installed and authenticated. We’ll be working in three phases, each driven by a carefully crafted Codex prompt.

🎧 Is this actually vibe coding? By the loosest definition — describing intent in natural language and letting AI generate the code — yes. But 2026’s usage has split into a spectrum. On one end sits “slop coding”: accepting whatever the agent produces with no review, which is how vibe-coded side projects rack up technical debt fast. On the other end is what this post demonstrates — natural-language prompts plus a standing AGENTS.md spec, a diff to review before every write, and a test suite the agent has to satisfy. Same vibe, considerably less slop.

Completed 8×8 Knight's Tour board generated by the Warnsdorff solver, showing move order numbers and the knight's path traced across the board

The completed tour from this walkthrough’s own solver — the full 8×8 board, all 64 moves, generated by the exact code Codex wrote below.

♞ What is the Knight’s Tour Problem?

The Knight’s Tour is a classic puzzle from combinatorics and graph theory: given an n×n chessboard and a knight placed on any starting square, can the knight visit every square on the board exactly once using only valid knight moves? A knight moves in an L-shape — two squares in one direction and one square perpendicular, giving it up to eight possible moves from any position.

The problem has been studied for over a thousand years. Arab mathematicians documented it as early as the 9th century, and Leonhard Euler conducted a systematic mathematical analysis in 1759. There are two variants: an open tour, where the starting and ending squares differ, and a closed (re-entrant) tour, where the knight can return to its starting square in one move. On the standard 8×8 board, there are over 26 trillion distinct open tours.

From an algorithmic standpoint, the Knight’s Tour is a special case of the Hamiltonian path problem on a graph, where each square is a node and edges connect squares reachable by a knight move. Finding a Hamiltonian path is NP-complete in general, but the regular structure of the chessboard makes efficient heuristics possible.

The most well-known heuristic is Warnsdorff’s rule (H.C. von Warnsdorff, 1823): at each step, move to the unvisited square that has the fewest onward moves. This greedy approach runs in linear time relative to the number of squares and finds a tour almost always on boards of size 5×5 and above — which is exactly what we’ll ask Codex to implement.

🗺️ What We’re Building

By the end of this walkthrough, we’ll have a fully working Python application with three layers built up incrementally through Codex prompts:

PhaseWhat Codex BuildsOutput
Phase 1Core solver using Warnsdorff’s heuristicCLI app, ASCII board output
Phase 2Pytest test suite and colourised terminal outputANSI colour board, passing tests
Phase 3Flask web app with animated HTML canvasInteractive browser visualisation

⚙️ Prerequisites

Before starting, make sure you have:

  • Codex CLI installed (brew install --cask codex or npm i -g @openai/codex)
  • Authenticated with a ChatGPT Plus/Pro account or an OpenAI API key
  • Python 3.10+ available in your shell
  • Git installed on your machine (see Project Setup below if you haven’t configured it yet)

📁 Project Setup

We’ll use Git throughout this guide as a safety net — you can git diff to review what Codex changed, or revert entirely if a phase goes wrong. If this is your first time using Git on this machine, configure your identity first:

git config --global user.name  "Your Name"
git config --global user.email "[email protected]"

This only needs to be done once. To verify your settings at any time:

git config --global --list

Now create the project directory, initialise the repo, and add an empty conftest.py in the root. The conftest.py file signals to pytest that the project root is the base directory, which allows it to resolve imports like from knight_tour import solve correctly from within the tests/ subdirectory:

mkdir knights-tour && cd knights-tour
git init
touch conftest.py
git commit --allow-empty -m "initial commit"

With the repo ready, launch Codex from inside the project directory:

codex

Once the TUI loads, your very first prompt should be to generate an AGENTS.md file. This acts as a standing project-level system prompt — Codex reads it automatically at the start of every future session, so you don’t have to repeat your conventions each time.

📝 Codex Prompt — Generate AGENTS.md

“Create an AGENTS.md file in the project root for a Python CLI and web application project. Include the following standing instructions: use Python 3.10+ with type hints throughout; place all tests in a /tests directory using pytest; never use global mutable state; prefer functions over classes unless OOP is genuinely the better fit; handle all CLI arguments with argparse; use Flask for any web routes; keep each module focused on a single responsibility. Format it as a markdown file with a brief intro line followed by a bullet list.”

Codex will create the file and show you the diff to review. Accept it, then commit before moving to Phase 1. Every subsequent Codex session in this directory will pick up these rules automatically.

💡 Why prompt Codex to write AGENTS.md instead of writing it yourself? Two reasons. First, you describe your intent conversationally rather than worrying about format. Second, it sets the right mental model for the rest of the guide — Codex writes the files, you review the diffs.

You can also update it at any time: “Add a rule that all functions must have docstrings” or “Update AGENTS.md to say we’re now using FastAPI instead of Flask” — Codex will edit the file in place and show you the diff.

Phase 1 — Core Solver

Still in the same Codex session, enter the Phase 1 prompt. Codex already has the project context from AGENTS.md, so you can get straight to the point:

📝 Codex Prompt — Phase 1

“Create a Python CLI app that solves the Knight’s Tour problem. Use Warnsdorff’s heuristic: at each step, move to the unvisited square with the fewest onward moves. The board size and starting position should be configurable via argparse using the argument names –size (default 8), –row (default 0), and –col (default 0). Do not use single-letter short flags. The solver should return None if no tour is found. Display the completed board as a grid of move numbers, right-aligned. Save the solver logic in knight_tour.py and the entry point in main.py. Include a requirements.txt (even if empty for now) and a .gitignore for Python.”

Codex will show you its plan before making any changes. In Auto mode, you’ll see it create each file with a diff preview. Here’s a simplified version of what the generated knight_tour.py looks like:

MOVES = [(2,1),(2,-1),(-2,1),(-2,-1),(1,2),(1,-2),(-1,2),(-1,-2)]

def get_neighbours(x, y, n, visited):
    return [(x+dx, y+dy) for dx,dy in MOVES
            if 0 <= x+dx < n and 0 <= y+dy < n
            and not visited[x+dx][y+dy]]

def solve(n, start_x, start_y):
    visited = [[False]*n for _ in range(n)]
    board   = [[-1]*n   for _ in range(n)]
    x, y = start_x, start_y
    visited[x][y] = True
    board[x][y]   = 0
    for move in range(1, n*n):
        neighbours = get_neighbours(x, y, n, visited)
        if not neighbours:
            return None
        x, y = min(neighbours,
                   key=lambda p: len(get_neighbours(p[0],p[1],n,visited)))
        visited[x][y] = True
        board[x][y]   = move
    return board

Run it in a separate terminal to verify:

python3 main.py --size 8 --row 0 --col 0

You should see a numbered 8×8 grid where each number represents the move order of the knight. Commit the result before moving to Phase 2.

💡 Approval Flow: In Codex’s default Auto mode, you’ll see a diff for each file before it’s written. Press A to accept or R to reject. If Codex proposes something you don’t want, reject it and follow up with a corrective prompt — it retains full context.

Phase 2 — Tests & Colourised Output

In the same Codex session, enter the next prompt. You don’t need to re-explain the project — Codex still has full context from Phase 1.

Before entering the prompt, install pytest in a separate terminal. Codex will attempt to run the test suite as part of its workflow, so the package must be present beforehand:

pip3 install pytest
📝 Codex Prompt — Phase 2

“Now add two things. First, create a test suite in tests/test_knight_tour.py using pytest. Test that: (1) solve() returns a valid tour where every integer from 0 to n²−1 appears exactly once, (2) consecutive moves are a valid knight’s move apart, (3) solve() returns None for n=2 which has no solution. Second, add a new function print_coloured_board() in knight_tour.py that uses ANSI escape codes to colour the board — alternate between a light and dark background for a chess-style pattern, with white text for the move numbers. Call it from main.py instead of format_board() when –colour flag is passed.”

Codex will generate the test file and extend knight_tour.py with the colour function. Key tests:

import pytest
from knight_tour import solve

def is_valid_knight_move(x1, y1, x2, y2):
    dx, dy = abs(x2-x1), abs(y2-y1)
    return (dx, dy) in {(1,2),(2,1)}

@pytest.mark.parametrize("n,r,c", [(5,0,0),(6,1,1),(8,0,0),(8,3,4)])
def test_valid_tour(n, r, c):
    board = solve(n, r, c)
    assert board is not None
    flat = sorted(v for row in board for v in row)
    assert flat == list(range(n*n))

def test_no_solution_n2():
    assert solve(2, 0, 0) is None

Run the tests in a separate terminal to verify. If you created conftest.py in the project root during setup, pytest will resolve imports correctly:

pytest tests/ -v

If you see a ModuleNotFoundError: No module named 'knight_tour', use the module invocation instead, which explicitly adds the project root to sys.path:

python3 -m pytest tests/ -v

And try the colour flag:

python3 main.py --size 8 --colour

Phase 3 — Flask Web App with Animated Visualisation

Now we go beyond the terminal. In the same session (or a fresh one — Codex resumes from codex resume --last), enter the Phase 3 prompt:

📝 Codex Prompt — Phase 3

“Add a Flask web app in app.py. It needs two routes: GET / serves a single-page HTML form where users can input board size (5–10) and starting row/col. POST /solve accepts these inputs, runs the solver, and returns the board as JSON. The HTML page should also contain a JavaScript canvas visualisation that animates the knight’s path one move at a time when the solution arrives — draw the board as a grid, colour visited squares progressively, and draw a ♞ symbol on the current square. Add flask to requirements.txt.”

Codex generates app.py and embeds the full HTML/JS using Flask’s render_template_string. The key backend endpoint:

from flask import Flask, request, jsonify, render_template_string
from knight_tour import solve
app = Flask(__name__)

@app.route("/solve", methods=["POST"])
def solve_tour():
    data = request.get_json()
    n, row, col = int(data.get("size",8)), int(data.get("row",0)), int(data.get("col",0))
    if not (5 <= n <= 10):
        return jsonify({"error": "Board size must be between 5 and 10"}), 400
    board = solve(n, row, col)
    if board is None:
        return jsonify({"error": "No solution found"}), 422
    return jsonify({"board": board, "n": n})

Install Flask and run:

pip3 install flask
python3 app.py

Visit http://localhost:5000, choose your board size and starting square, hit Solve, and watch the knight’s path animate across the canvas.

🔄 Iterating Further — More Prompt Ideas

Once your three-phase app is working, you can keep iterating in the same session. Here are some prompts to take it further:

GoalFollow-up Prompt
Speed comparison“Add a backtracking solver as an alternative to Warnsdorff’s. Add a –solver flag to switch between them, and time both with Python’s timeit.”
Export result“Add a –export flag to main.py that saves the board as a CSV and also renders it as a PNG using matplotlib, with the knight path drawn as a line.”
User clicks board“Update the web app so users click a cell on the canvas to set the starting position instead of using the form fields.”
Code review“Review the current codebase for edge cases, type annotation completeness, and any issues with the input validation in app.py.”

✅ Effective Prompting Tips for Codex

A few patterns that made a noticeable difference in the quality of output across this walkthrough:

TipWhy It Helps
Name your files explicitlyCodex won’t guess at naming conventions. Saying “save to knight_tour.py” prevents it from choosing arbitrary filenames.
Specify what None/failure meansWithout “return None if no tour is found,” Codex might raise an exception instead — a valid choice but harder to test.
Bundle related changes in one promptPhase 2 added tests and colour output together. Codex handles multi-file tasks well when given in a single cohesive prompt.
Keep sessions alive for follow-upsDon’t exit and re-enter. Staying in the same session means Codex retains full context — you can make corrections without re-explaining the project.
Use AGENTS.md for standing rulesAnything you’d say in every prompt belongs in AGENTS.md. It keeps prompts shorter and ensures consistent style across sessions.

📁 Final Project Structure

knights-tour/
├── AGENTS.md
├── conftest.py           ← empty, anchors pytest to project root
├── .gitignore
├── requirements.txt      ← flask
├── knight_tour.py        ← solver + display logic
├── main.py               ← CLI entry point
├── app.py                ← Flask web app
└── tests/
    └── test_knight_tour.py

What’s worth noticing in this walkthrough is the workflow rhythm: each Codex prompt builds on the last without re-explaining context, and the AGENTS.md file silently enforces project conventions so you don’t have to. The three phases took roughly 15 minutes end-to-end, most of which was reviewing diffs and running tests rather than writing code — not a single line was typed by hand.

The Knight’s Tour is just the illustration. The same prompt-iterate-commit loop applies to any project — and the more you invest in a good AGENTS.md upfront, the more useful each Codex session becomes.

This is what vibe coding looks like once it graduates past the demo-day stunt: still driven entirely by natural language, still fast, but with a spec file, a diff review, and a test suite standing between “the agent wrote it” and “it shipped.”

Word Embeddings Explained: The Math Behind AI, LLMs, and Chatbots

NLP Explainer · AI Series 2026

How Machines Understand Language

A guide to word embeddings — where meaning becomes mathematics, and vectors do the talking.

When a search engine retrieves a document about automobiles in response to a query about cars, it is not matching text character by character. Somewhere beneath the interface, the system understands that these two words are semantically related. The mechanism behind that understanding is the word embedding — and once you see the geometry, you cannot unsee it.

This article walks through the key mathematical operations that make embeddings work: distance, similarity, arithmetic, scaling, and the dot product. Each concept is illustrated with concrete numerical vectors so the math is visible, not just described. Real embeddings typically use hundreds of dimensions; the 3- and 4-dimensional examples here preserve all the structure while staying readable on a page.

1  ·  What is a Word Embedding?

A word embedding is a representation of a word as a vector — an ordered list of numbers — in a high-dimensional space. A typical embedding model might use 300 dimensions, so the word cat becomes a point with 300 coordinates. That sounds abstract, but the key insight is this: the position of that point encodes meaning.

This is what researchers call a semantic space. Words with related meanings end up positioned close to each other. King and Queen live near each other. Paris and London live near each other. Bicycle and democracy live far apart. The model learns these positions not from human-curated rules, but from the statistical patterns of how words appear together in enormous text corpora.

EXAMPLE: 4-DIMENSIONAL VECTORS (simplified from real 300-dim embeddings)
vec(“King”)  = [ 0.9, 0.7, 0.4,  +0.6 ]
vec(“Queen”)  = [ 0.9, 0.7, 0.4,  -0.6 ]
vec(“Man”)  = [ 0.5, 0.3, 0.1,  +0.8 ]
vec(“Woman”) = [ 0.5, 0.3, 0.1,  -0.8 ]

The first three dimensions encode royalty, authority, and age.
The fourth dimension encodes gender: positive = masculine, negative = feminine.

Think of it as a map where the geography is meaning. Every word is a pin, and the distances between pins reflect semantic relationships rather than physical ones.

2  ·  The Geometry of Meaning: Distance and Similarity

Once words are points in space, we need a way to measure how close they are. Two approaches dominate: Euclidean distance and cosine similarity. For the examples below, we use a 3-dimensional temperature embedding:

TEMPERATURE VECTORS (3 dimensions)
vec(“Hot”) = [  1.0,  0.8,  0.6 ]
vec(“Warm”) = [  0.8,  0.6,  0.4 ]
vec(“Cold”) = [ -0.6,  0.4, -0.8 ]

2.1   Euclidean (Cartesian) Distance

The most intuitive measure — the straight-line gap between the tips of two arrows drawn from the origin. For vectors a and b in n dimensions:

d(a, b)  =  √ Σi ( aibi )2
WORKED EXAMPLE: EUCLIDEAN DISTANCE
// Hot vs Warm (similar words)
d(Hot, Warm) = √[ (1.0-0.8)2 + (0.8-0.6)2 + (0.6-0.4)2 ]
              = √[ 0.04 + 0.04 + 0.04 ] = √0.12  &approx;  0.346  ← small: close together

// Hot vs Cold (opposite words)
d(Hot, Cold) = √[ (1.0-(-0.6))2 + (0.8-0.4)2 + (0.6-(-0.8))2 ]
              = √[ 2.56 + 0.16 + 1.96 ] = √4.68  &approx;  2.163  ← large: far apart

2.2   Cosine Similarity — The Industry Standard

In practice, NLP systems almost universally prefer cosine similarity over Euclidean distance. It ignores the length of vectors entirely and focuses only on the angle between them — two vectors pointing the same direction score 1.0 regardless of their magnitude.

COSINE SIMILARITY
cos(θ)  = a  ·  b
a‖  ×  ‖b
Range: −1  (opposite)  →  0  (orthogonal)  →  +1  (identical direction)
WORKED EXAMPLE: COSINE SIMILARITY
// First compute magnitudes
‖Hot‖ = √(1.02 + 0.82 + 0.62) = √2.00 &approx; 1.414
‖Warm‖ = √(0.82 + 0.62 + 0.42) = √1.16 &approx; 1.077
‖Cold‖ = √(0.62 + 0.42 + 0.82) = √1.16 &approx; 1.077

// Hot vs Warm (small angle)
dot(Hot, Warm) = (1.0)(0.8) + (0.8)(0.6) + (0.6)(0.4) = 0.80 + 0.48 + 0.24 = 1.52
cos(Hot, Warm) = 1.52 / (1.414 × 1.077) = 1.52 / 1.523 &approx; +0.998

// Hot vs Cold (large angle)
dot(Hot, Cold) = (1.0)(-0.6) + (0.8)(0.4) + (0.6)(-0.8) = -0.60 + 0.32 – 0.48 = -0.76
cos(Hot, Cold) = -0.76 / (1.414 × 1.077) = -0.76 / 1.523 &approx; -0.499
Word Pair Euclidean d cos(θ) Interpretation
Hot vs Warm 0.346 +0.998 Nearly identical direction — closely related
Hot vs Cold 2.163 −0.499 Opposite directions — antonyms
3  ·  Vector Arithmetic: Meaning You Can Add and Subtract

Because words are vectors, you can perform arithmetic on them — and the results are semantically meaningful. The most famous example uses the 4-dimensional royalty vectors introduced in Section 1:

THE CLASSIC ANALOGY
vec(“King”) − vec(“Man”) + vec(“Woman”)  &approx;  vec(“Queen”)
WORKED EXAMPLE: KING – MAN + WOMAN
King  = [ 0.9,  0.7,  0.4,  +0.6 ]
Man  = [ 0.5,  0.3,  0.1,  +0.8 ]
Woman  = [ 0.5,  0.3,  0.1,  -0.8 ]

// Subtract component by component, then add
King – Man = [ 0.9-0.5,  0.7-0.3,  0.4-0.1,  0.6-0.8 ] = [  0.4,   0.4,   0.3,  -0.2 ]
+ Woman   = [ 0.4+0.5,  0.4+0.3,  0.3+0.1,  -0.2+(-0.8) ] = [  0.9,   0.7,   0.4,  -1.0 ]

// Find nearest word by Euclidean distance
result = [ 0.9, 0.7, 0.4, -1.0 ]

d(result, Queen) = √[ 0 + 0 + 0 + (-1.0-(-0.6))2 ] = √0.16 &approx; 0.400 ← nearest
d(result, Woman) &approx; 0.671    d(result, King) = 1.600    d(result, Man) &approx; 1.910

cos(result, Queen) &approx; 0.974   ← highest cosine similarity also points to Queen

What happened geometrically? Subtracting Man from King stripped out the gender dimension (+0.8 gone), leaving the royalty structure intact. Adding Woman injected the feminine gender value (-0.8). The result sits 0.4 units from Queen — the nearest word in this vocabulary.

4  ·  Scalar Multiplication and Division: Changing Intensity

Multiplying or dividing a vector by a scalar (a plain number) changes its magnitude without changing its direction. This maps neatly onto the idea of degree in language — Tiny, Large, and Gigantic all point in roughly the same semantic direction, but at different intensities.

SIZE VECTORS (3 dimensions)
vec(“Tiny”) = [ 0.10, 0.20, 0.10 ]
vec(“Large”) = [ 0.50, 0.70, 0.40 ]
vec(“Gigantic”) = [ 1.10, 1.50, 0.90 ]
WORKED EXAMPLE: SCALING ALONG THE SIZE AXIS
// Multiplying Large by 2 moves it toward Gigantic
Large × 2 = [ 0.5×2,  0.7×2,  0.4×2 ] = [ 1.00,  1.40,  0.80 ]
vec(“Gigantic”) = [ 1.10,  1.50,  0.90 ]    d(Large × 2, Gigantic) &approx; 0.173 ← very close

// Multiplying Large by 0.2 moves it toward Tiny
Large × 0.2 = [ 0.10,  0.14,  0.08 ]
vec(“Tiny”) = [ 0.10,  0.20,  0.10 ]    d(Large × 0.2, Tiny) &approx; 0.063 ← very close

Division works the same way along an intensity axis. Halving a “Loud” vector lands near “Soft”:

WORKED EXAMPLE: DIVIDING ALONG THE LOUDNESS AXIS
vec(“Loud”) = [ 0.90, 1.20, 0.60 ]    vec(“Soft”) = [ 0.30, 0.40, 0.20 ]
Loud ÷ 2 = [ 0.45,  0.60,  0.30 ]
d(Loud ÷ 2, Soft) &approx; 0.269  ← direction unchanged, intensity halved
Key intuition: Scalar operations change how much of something a vector represents, without changing what kind of thing it represents. Direction is preserved; intensity is tuned.
5  ·  The Dot Product: Agreement and Magnitude Together

The dot product of two vectors is computed by multiplying their corresponding components and summing the results:

DOT PRODUCT
a  ·  b  =  Σi  ( ai × bi )  =  a1b1  +  a2b2  + … +  anbn

The dot product is cosine similarity before normalising away the vector lengths. It captures two things simultaneously: the direction of agreement and the combined magnitude. Cosine similarity captures only the first.

We reuse the loudness vectors from Section 4 — Very Loud is “Loud” and A Little Loud is “Soft”. They point in exactly the same direction but have very different lengths:

WORKED EXAMPLE: VERY LOUD vs A LITTLE LOUD
vec(“A Little Loud”) = [ 0.30, 0.40, 0.20 ]  |magnitude| = 0.539
vec(“Very Loud”) = [ 0.90, 1.20, 0.60 ]  |magnitude| = 1.616

// Cosine similarity: measures direction only
dot(AL, VL) = (0.3)(0.9) + (0.4)(1.2) + (0.2)(0.6) = 0.27 + 0.48 + 0.12 = 0.87
cos(AL, VL) = 0.87 / (0.539 × 1.616) = 0.87 / 0.871 &approx; 1.000

// Dot product: measures direction AND magnitude
AL · AL = (0.3)2 + (0.4)2 + (0.2)2 = 0.09 + 0.16 + 0.04 = 0.29
VL · VL = (0.9)2 + (1.2)2 + (0.6)2 = 0.81 + 1.44 + 0.36 = 2.61
Comparison Magnitude cos(θ) v · v
A Little Loud 0.539 1.000 (same dir.) 0.29
Very Loud 1.616 1.000 (same dir.) 2.61

Both words are perfectly collinear — cosine similarity is 1.0 in both cases. But the dot products are 0.29 vs 2.61, a 9× difference. This is why recommendation systems and attention mechanisms in transformer models often prefer raw dot products: when you want to know not just whether a document is relevant but also how prominently it discusses a topic, the dot product gives you both dimensions at once.

6  ·  Practical Applications

Search engines convert your query into a vector and retrieve documents whose vectors are nearest to it in the semantic space — using cosine similarity to rank by relevance regardless of exact word match. When you search for car insurance and the engine returns results about vehicle coverage, it is doing nearest-neighbour lookup in embedding space, exactly as the Hot/Warm/Cold example in Section 2 demonstrates.

Recommendation systems represent your interests as a vector computed from your history, then find products whose vectors are closest to yours. The dot product is particularly useful here: a highly-relevant item with a large magnitude — analogous to Very Loud — will score higher than a mildly-relevant item even if they point in the same direction.

Large language models use the scaled dot product directly inside the attention mechanism. For every token, a query vector and a set of key vectors are compared via dot product to determine which parts of the context deserve attention — a direct descendant of the arithmetic explored in Section 5.

Quick Reference: Embedding Operations

Operation Formula Section 2-5 Result
Euclidean Distance √( Σ (aibi)2 ) d(Hot,Warm) = 0.346   d(Hot,Cold) = 2.163
Cosine Similarity (a·b) / (‖a‖×‖b‖) cos(Hot,Warm) = +0.998   cos(Hot,Cold) = -0.499
Vector Arithmetic a ± b King-Man+Woman → nearest Queen (d = 0.400)
Scalar Multiplication λ · a Large × 2 → near Gigantic   Loud ÷ 2 → near Soft
Dot Product a·b = Σ aibi cos = 1.00 for both; dot 0.29 (soft) vs 2.61 (loud)

✦ This article was generated with the assistance of Claude by Anthropic