Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions content/current-article.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

_Introducing PolicyEngine's newest AI-powered tool to help users understand UK tax and benefit policy_

_11 August 2026_

People are increasingly turning to AI language models to answer complex questions about tax and benefit policy and reform because models can read loosely worded questions and answer them in plain language. This presents a problem: for many users, tax and benefit questions directly affect their lives and livelihoods, so they require correct, verifiable answers. Language models generate responses from learned statistical patterns, and an answer may be partly or wholly wrong.

PolicyEngine therefore built UK Chat, an AI interface to PolicyEngine's deterministic rules and simulation engine. A language model interprets an open-ended request and proposes a structured plan. The gateway checks the proposed inputs and output against the current PolicyEngine catalogue; only then do deterministic tools compute quantitative policy results from actual tax and benefit rules.
Expand Down
109 changes: 57 additions & 52 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,6 @@ function Hero() {
Introducing PolicyEngine's newest AI-powered tool to help users understand UK tax and benefit
policy
</p>
<p className="article-date">
<time dateTime="2026-08-11">11 August 2026</time>
</p>
</FadeIn>
);
}
Expand Down Expand Up @@ -441,153 +438,161 @@ function BoundaryDiagram() {
<rect
x="20"
y="40"
width="380"
width="410"
height="220"
rx="14"
fill="rgba(13,115,119,0.05)"
stroke="var(--accent)"
strokeWidth="1.5"
strokeDasharray="8 5"
/>
<text x="210" y="66" className="lane-label" fill="#0d7377">
<text x="225" y="66" className="lane-label" fill="#0d7377">
PREDICTIVE — LANGUAGE MODEL
</text>

<rect
x="500"
x="470"
y="40"
width="380"
width="410"
height="220"
rx="14"
fill="rgba(44,100,150,0.05)"
stroke="#2c6496"
strokeWidth="1.5"
strokeDasharray="8 5"
/>
<text x="690" y="66" className="lane-label" fill="#2c6496">
<text x="675" y="66" className="lane-label" fill="#2c6496">
DETERMINISTIC — POLICYENGINE UK
</text>

<rect x="50" y="88" width="150" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="125" y="112" className="network-label">
<rect x="38" y="88" width="175" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="125" y="111" className="network-label">
Interpret the
</text>
<text x="125" y="130" className="network-label">
<text x="125" y="131" className="network-label">
question
</text>

<rect x="220" y="88" width="150" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="295" y="112" className="network-label">
<rect x="237" y="88" width="175" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="324" y="111" className="network-label">
Choose a tool
</text>
<text x="295" y="130" className="network-label">
<text x="324" y="131" className="network-label">
and arguments
</text>

<rect x="135" y="176" width="150" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="210" y="200" className="network-label">
<rect x="138" y="176" width="175" height="56" rx="10" fill="#fff" stroke="#0d7377" strokeWidth="2" />
<text x="225" y="199" className="network-label">
Explain the
</text>
<text x="210" y="218" className="network-label">
<text x="225" y="219" className="network-label">
returned numbers
</text>

<rect x="530" y="88" width="150" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="605" y="112" className="network-label">
<rect x="488" y="88" width="175" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="575" y="111" className="network-label">
Validate
</text>
<text x="605" y="130" className="network-label">
<text x="575" y="131" className="network-label">
and look up
</text>

<rect x="700" y="88" width="150" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="775" y="112" className="network-label">
<rect x="687" y="88" width="175" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="774" y="111" className="network-label">
Simulate
</text>
<text x="775" y="130" className="network-label">
<text x="774" y="131" className="network-label">
baseline + reform
</text>

<rect x="615" y="176" width="150" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="690" y="200" className="network-label">
<rect x="588" y="176" width="175" height="56" rx="10" fill="#fff" stroke="#2c6496" strokeWidth="2" />
<text x="675" y="199" className="network-label">
Weighted outputs
</text>
<text x="690" y="218" className="network-label">
<text x="675" y="219" className="network-label">
and chart rows
</text>

<line
x1="450"
y1="30"
x2="450"
y2="270"
stroke="#1a202c"
strokeWidth="2"
strokeDasharray="4 6"
opacity="0.45"
/>
{/* Broken into three segments so the two crossing captions sit in the gap
between the lanes without the dashed line running through them. */}
{[
[30, 92],
[116, 182],
[196, 270],
].map(([y1, y2]) => (
<line
key={y1}
x1="450"
y1={y1}
x2="450"
y2={y2}
stroke="#1a202c"
strokeWidth="2"
strokeDasharray="4 6"
opacity="0.45"
/>
))}
<text x="450" y="22" className="lane-label boundary-label" fill="#1a202c">
TYPED TOOL BOUNDARY
</text>

<line
x1="200"
x1="213"
y1="116"
x2="216"
x2="231"
y2="116"
className="boundary-connector"
strokeWidth="1.8"
strokeLinecap="round"
markerEnd="url(#boundary-arrow)"
/>
<line
x1="370"
x1="412"
y1="116"
x2="526"
x2="484"
y2="116"
className="boundary-connector"
strokeWidth="1.8"
strokeLinecap="round"
markerEnd="url(#boundary-arrow)"
/>
<text x="448" y="106" className="network-label flow-caption">
<text x="450" y="104" className="network-label flow-caption">
tool call
</text>
<line
x1="680"
x1="663"
y1="116"
x2="696"
x2="681"
y2="116"
className="boundary-connector"
strokeWidth="1.8"
strokeLinecap="round"
markerEnd="url(#boundary-arrow)"
/>
{/* Simulate (x 700-850) and Weighted outputs (x 615-765) overlap between
700 and 765, so the two are joined by a plain vertical drop through the
middle of that overlap. Curving between their centres put the head in
at an angle, floating short of the box. */}
{/* Simulate (x 687-862) and Weighted outputs (x 588-763) overlap between
687 and 763, so a plain vertical drop through the middle of that
overlap meets the box squarely. */}
<line
x1="732"
x1="725"
y1="144"
x2="732"
x2="725"
y2="172"
className="boundary-connector"
strokeWidth="1.8"
strokeLinecap="round"
markerEnd="url(#boundary-arrow)"
/>
<line
x1="611"
x1="584"
y1="204"
x2="289"
x2="317"
y2="204"
className="boundary-connector"
strokeWidth="1.8"
strokeLinecap="round"
markerEnd="url(#boundary-arrow)"
/>
<text x="450" y="194" className="network-label flow-caption">
<text x="450" y="192" className="network-label flow-caption">
typed result
</text>
</svg>
Expand Down
47 changes: 23 additions & 24 deletions src/uk-chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -149,13 +149,13 @@
.boundary-flow-svg .network-label {
fill: var(--text-mid);
font-family: 'JetBrains Mono', monospace;
font-size: 13px;
font-size: 15px;
text-anchor: middle;
}

.boundary-flow-svg .lane-label {
font-family: 'JetBrains Mono', monospace;
font-size: 11px;
font-size: 12.5px;
font-weight: 700;
letter-spacing: 0.12em;
text-anchor: middle;
Expand All @@ -166,7 +166,7 @@
}

.boundary-flow-svg .flow-caption {
font-size: 11px;
font-size: 12px;
}

.boundary-flow-svg .boundary-connector {
Expand Down Expand Up @@ -553,6 +553,18 @@
}

@media (max-width: 600px) {
/* The label and the count crowd each other on a phone. */
.card-tabs-header {
align-items: flex-start;
flex-direction: column;
gap: 4px;
}

/* .agent-flow-container's 60px of top padding is most of a phone screen. */
.boundary-flow-container {
padding: 44px 14px 26px;
}

.tool-cards {
grid-template-columns: 1fr;
}
Expand Down Expand Up @@ -598,31 +610,11 @@
results-table caveat and every card meta line. Darkened at the token in
legacy-encode-policy.css; these are the knock-on fixes. */

/* 18px serif across a 1160px wrapper runs to ~140 characters a line. Cap the
measure without narrowing the diagrams, tables, and card grids. */
.article-wrapper > div > p,
.article-wrapper > div > ul,
.article-wrapper > div > ol,
.article-wrapper .step-content p,
.article-wrapper .subtitle {
max-width: 78ch;
}

.article-date {
color: var(--text-mid);
font-family: 'JetBrains Mono', monospace;
font-size: 0.78rem;
letter-spacing: 0.04em;
margin-top: -34px;
margin-bottom: 50px;
text-transform: uppercase;
}

/* max-width: 100% stopped .agent-flow-container's overflow-x from ever
engaging, so on a phone the 900-unit diagram shrank its labels to ~3.5px.
A min-width lets the container scroll instead. */
.boundary-flow-svg {
min-width: 620px;
min-width: 700px;
}

/* Keyboard focus looked identical to the selected tool, so two chips read as
Expand Down Expand Up @@ -677,3 +669,10 @@
flex-wrap: wrap;
gap: 8px;
}

/* The diagram is the densest thing on the page; give it more of the wrapper
than .agent-flow-container's default 40px side padding allows. */
.boundary-flow-container {
padding-left: 20px;
padding-right: 20px;
}
Loading