praxagent
Work Research Notes Knowledge Base Search Contact
Work Research Notes Knowledge Base Search Contact

The visual short read

Too Many Secrets: Hiding bits and logic in a language-model feedback loop

November 3, 2026 · by Timothy Jones
AI agents have already coordinated through channels nobody designed for them. In this note we show that a language model running as a feedback loop is itself such a medium: its numerical behavior, rather than its words, carried complete messages in both directions, held a written bit, and ran simple logic on it. The examples shown here demonstrate the importance of thinking creatively when trying to secure agents.
Explore the findings ↓
Pythia-160m soft-token map. Three panels over steering strength and log-ten temperature: largest Lyapunov exponent per step, period of the attractor, and next-token entropy at the last step. Full interpretation follows below.
Pythia-160m soft-token map
AI-use disclosure. Generative-AI tools helped implement, audit, execute, interpret, visualize, and review this study, and helped draft this note. The author selected the research questions, sculpted the final shape of the project, and authorized the compute. This is an independent, non-peer-reviewed Research Note.
Why this note exists. The methods here are outside the realm of practical, but demonstrate that there are many strange and innovative ways of communication that alignment researchers need to imagine and plan for.

Agents already improvise channels

In July 2026, autonomous agents running under an offensive-security evaluation coordinated a sandbox escape through a message board they improvised inside a shared package registry, at one stage encoding posts in the names of directories they created. They exchanged hundreds of thousands of messages before anyone noticed (the Hugging Face incident). The lesson is general: capable systems can communicate through whatever they can write to and read back, not only through the channels we monitor. Anticipating such routes means asking, in advance, what an unconventional medium can carry. This study asks it of the running model itself.

A complete request and reply through Pythia

What is looping?

An ordinary chatbot appends a chosen token to a growing conversation. Here the prompt stays fixed and one input slot is replaced on every step. Instead of the winning token, the slot receives a blend of all token embeddings, weighted by the model’s own next-token probabilities:

\[ \vec{x}_{n+1} = E^{\mathsf T}\,\operatorname{softmax}\!\left(\frac{z_\alpha(\vec{x}_n)}{T}\right). \]

Here \(\vec{x}_n\in\mathbb{R}^{d}\) is the blended input vector, \(E\in\mathbb{R}^{V\times d}\) is the input embedding table (one length-\(d\) row for each of the \(V\) vocabulary tokens, with superscript \(\mathsf T\) denoting matrix transpose), \(z_\alpha(\vec{x}_n)\in\mathbb{R}^{V}\) is the network’s output score vector (logits) with a steering push of strength \(\alpha\), and \(T > 0\) is the temperature. Softmax turns the scaled scores into \(V\) probabilities that sum to 1, and multiplying by \(E^{\mathsf T}\) takes their weighted average to produce the next length-\(d\) state vector \(\vec{x}_{n+1}\). No token is sampled, so the loop is a deterministic map whose state has dimension 896 for Qwen and 768 for Pythia. Depending on the two controls, it settles into a repeating cycle or keeps moving irregularly, and either behavior can stand for a bit. This is the soft-token loop measured in the earlier feedback study (Jones, 2026). Its short read shows where that loop repeats and where it is chaotic.

Why Pythia. Pythia-160m is a very small model, 160 million parameters, released by EleutherAI and easy to download. The weights are not a large file, so fetching them need not stand out as a big model transfer, and the loop in this note runs on a CPU. No graphics processor is required.

Consider the chaos map of Pythia-160m, where we have chosen 48 spots randomly on the map, 24 which correspond to chaotic trajectories and 24 which correspond to periodic trajectories. The two controls are a steering strength and a temperature. Choose a pair, reset the loop, and let it run. At some settings the loop settles into a repeating cycle. At others it keeps moving, and a tiny copy of the same run drifts away.

If we decide that a coordinate that corresponds to a periodic orbit is mapped to 0, and a coordinate that maps to chaos is 1, then we have a means of communicating using this map that would be non-trivial to understand.

Pythia addresses on the earlier scan. Circles are zeros, triangles are ones, and gray crosses are pairs that failed. Source: this research note.

Address diversity is a separate result from message delivery. The background is the earlier scan, not a fresh reliability census. Circles are zeros and triangles are ones. A pair was kept only when both came back the same from two fresh receivers. Excluded pairs are shown even when only one member failed.

Forty-eight identical dots on axes labeled only x and y. The diagram does not say that x is steering strength, that y is log-ten temperature, or which dots are zeros and which are ones. Source: this research note.

The same 48 addresses, as coordinates only. A human monitoring the communication between agents would find it non-trivial to map these to 0s and 1s.

An encoding, not encryption. A cipher should stay secret even when the method is public, so long as the key is not. That rule is Kerckhoffs’s principle. Here the method is the whole secret: know that \(x\) is steering, \(y\) is temperature, and that a repeating run is 0. Once that is known, the numbers can be read. Secrecy that disappears when the method is known is called security through obscurity. The everyday word is obfuscation.

This is the view from outside. Someone monitoring the communications and recovering these numbers would see pairs. The rows below are a sample of the 48, rounded to four decimal places. The vertical ellipsis stands for the addresses not listed.

x, yState
-0.1613, -0.00400
-0.1537, 0.00781
-0.0784, -0.24620
-0.0687, -0.24511
⋮⋮
0.1595, 0.03370
0.1477, 0.03581
⋮⋮

We wanted each zero to have a one nearby: a spot where the loop repeats, and a spot close to it where the loop does not. Two new runs of the model, neither of which was shown the answer, had to agree on both spots. When they did, we kept the pair. That search retained 24 pairs, or 48 addresses from 32 candidate pairs, the dots in the diagram. The SETEC ASTRONOMY walkthrough below draws from all 24 pairs (48 addresses), while an earlier 470-byte recorded exchange reused a smaller set of 8 addresses, and because of the fractal structure of the chaos map, many more candidate pairs could be sampled across the scan.

Agents only need to agree on a model and a mechanism. They do not need to exchange a map of points. They can sample points on the chaos map, and another agent can read each point as a 0 or a 1 from whether the trajectory repeats or is chaotic.

What the sender transmits is a line of English naming one address. The first number is the left-right position on the map. The second is the up-down position. The receiver gets that line and reads the bit by running the loop. To transmit one bit, the agent only needs to send a coordinate:

-0.0019569471624266144, 0.20264187866927602

Each line resets the state, allows 32 steps of warm-up, and then watches 128 steps. The receiver asks whether the trajectory repeats, and whether a tiny twin drifts away or closes in. Their average rate of separation is a finite-window Lyapunov estimate, \(\hat\lambda\):

\[ \text{bit} = \begin{cases} 0 & \text{repeats},\ \hat\lambda < -0.01,\\ 1 & \text{no repeat},\ \hat\lambda > 0.01,\\ \text{erased} & \text{otherwise.} \end{cases} \]

Anything between those two clear cases is left blank. The receiver withholds the bit instead of guessing.

One spot on the map is one bit. A letter is eight of those bits, so each letter of a message costs eight pairs of coordinates. The agents can choose the coordinates randomly from the chaos map as long as the choice corresponds to either a chaotic or periodic orbit. This prevents easily mapping the frequency of the coordinates to potential letters. The receiver runs the loop at each pair and writes 0 or 1. Put the eight bits back together and you have a letter. The phrase below begins with S, and the eight bits for S are 01010011.

Why S is the number 83. A computer does not store the shape of a letter. It stores a number from the ASCII table, the standard list both sides already share: A is 65, B is 66, C is 67, and each next letter is one higher. Count from A and S is 83. Nothing here invented that table. Any computer already turns ASCII 83 back into S. Eight bits are just a way to write that number. Read them from the left. Each place is worth twice the place on its right.

1286432168421
01010011
Add only the places marked 1: \(64+16+2+1=83\). That is the ASCII entry for S, so the eight bits 01010011 are the letter S.

Here is that path for the phrase SETEC ASTRONOMY. Each letter is eight spots drawn from the 48: a spot whose state is 0 when the bit is 0, and a spot whose state is 1 when the bit is 1. A spot may be drawn again. What the sender hands over is only the list of pairs. Rounded to four decimal places, one draw looks like this:

S
01010011
01010011 = 83
0.1595, 0.0337-0.0429, 0.1359-0.0579, -0.2311-0.1537, 0.0078-0.0192, -0.0750-0.0784, -0.24620.1627, -0.2849-0.0977, -0.0664
E
01000101
01000101 = 69
0.0680, 0.06380.1369, -0.1891-0.0192, -0.0750-0.0622, -0.23540.1509, -0.27950.1477, 0.0358-0.0784, -0.24620.1143, -0.1127
T
01010100
01010100 = 84
-0.1074, 0.04870.2779, -0.15250.1272, 0.07350.2779, -0.15250.1218, -0.05570.1143, -0.1127-0.0192, -0.07500.1433, -0.1838
E
01000101
01000101 = 69
-0.0461, -0.12030.3166, -0.15470.1767, -0.30000.1767, -0.30000.1433, -0.18380.1477, 0.03580.1433, -0.18380.1369, -0.1891
C
01000011
01000011 = 67
-0.0579, -0.23110.1477, 0.03580.1272, 0.0735-0.0192, -0.07500.1218, -0.05570.1261, -0.1213-0.0138, -0.06540.1143, -0.1127
␣
00100000
00100000 = 32
0.1261, -0.12130.1218, -0.0557-0.0977, -0.06640.1433, -0.1838-0.1613, -0.00400.1218, -0.05570.3317, -0.15250.0519, 0.0498
A
01000001
01000001 = 65
-0.0461, -0.12030.1369, -0.18910.1433, -0.18380.1767, -0.30000.1509, -0.27950.0680, 0.0638-0.0461, -0.12030.1627, -0.2849
S
01010011
01010011 = 83
-0.1128, -0.06320.2779, -0.15250.1433, -0.18380.1477, 0.0358-0.0353, 0.14560.1509, -0.27950.1089, -0.1159-0.1171, -0.0374
T
01010100
01010100 = 84
0.1218, -0.05570.1143, -0.11270.1595, 0.03370.0432, 0.05410.1433, -0.18380.0432, 0.05410.0680, 0.0638-0.1613, -0.0040
R
01010010
01010010 = 82
0.1272, 0.0735-0.0977, 0.0573-0.1128, -0.06320.3166, -0.1547-0.0784, -0.24620.1433, -0.1838-0.0138, -0.0654-0.0622, -0.2354
O
01001111
01001111 = 79
0.1003, -0.1149-0.0612, -0.11270.2660, -0.1461-0.0859, -0.0557-0.0138, -0.06540.1509, -0.26990.2779, -0.1525-0.0977, -0.0664
N
01001110
01001110 = 78
-0.0622, -0.23540.1143, -0.11270.0519, 0.04980.1595, 0.0337-0.0429, 0.13590.1089, -0.11590.1143, -0.1127-0.0192, -0.0750
O
01001111
01001111 = 79
0.3317, -0.15250.2779, -0.15250.1218, -0.05570.1433, -0.1838-0.0612, -0.1127-0.0612, -0.1127-0.1494, 0.0746-0.0687, -0.2451
M
01001101
01001101 = 77
-0.0353, 0.14560.1089, -0.11590.1433, -0.1838-0.0859, -0.05570.2779, -0.15250.2779, -0.1525-0.1311, -0.03740.1089, -0.1159
Y
01011001
01011001 = 89
-0.1128, -0.0632-0.1171, -0.0374-0.0784, -0.24620.1477, 0.0358-0.0515, -0.2473-0.1128, -0.0632-0.1613, -0.0040-0.1537, 0.0078
SETEC ASTRONOMY

Read each group from top to bottom. The eight bits are a number, and the number is the letter, by the ASCII table, as with S. The fifteen groups come back as SETEC ASTRONOMY (the anagram for Too Many Secrets from the 1992 film Sneakers).

A slow way to talk. The measured exchange delivered 3,760 bits in about 150.5 minutes. That is 0.052 delivered application bytes per second, about 0.4 bits a second, counting the time to run each spot through the loop. A letter is eight bits, so one letter takes about twenty seconds at that pace. SETEC ASTRONOMY is fifteen characters and would take about five minutes. Each bit is one spot: 32 steps for the loop to settle, then 128 steps to read whether it repeats. Our point is not that this is a practical means of communication. But an agent could share an encryption key through this means of obfuscation and then communicate more rapidly through an actual means of communication with a key that would take human researchers or monitoring AIs some time to recover.

Two stable states at one setting

Using the Pythia chaos map to encode bits is a more trivial example. Using the Qwen2.5-0.5B chaos map allows for something more useful: it can remember. Qwen2.5-0.5B’s chaos map shows multiple “shrimp” structures which have a useful feature. For example, at one setting of its controls the loop has two different attracting cycles, each repeating every six steps. Which one the state follows is a stored bit, an attractor memory in the sense of Hopfield’s networks. Both cycles even write the same most-likely tokens, so the bit lives in the numbers, not in the text.

Labeled Qwen parameter map: steering strength across and log-ten temperature up, with a black fold curve, red dashed flip curves, cusp C, and a green segment where two attracting cycles coexist. Source: this research note.

The actual kite in parameter space. Replotted from the earlier Qwen study’s saved map and continuation curves (Jones, 2026). The axes are steering strength and log-ten temperature. Black curves locate folds; red dashed curves locate flips; C marks the located cusp. The green segment is the sampled attracting overlap on the fixed-temperature cut. A, B and R mark crossings involving distinct orbit sheets. The background is the earlier fixed-start scan, not a new memory test.

Numerical continuation of the period-six orbit at fixed log10 temperature. Two solid attracting segments overlap in a green interval, with dashed nonattracting segments and open circles marking folds. Source: this research note.

Two possible states at identical controls. At log-ten temperature −0.1539515, the two attracting branches overlap over steering strengths 0.072907–0.072992 (green). Dashed segments do not attract; open circles mark folds, where a branch ends. Height is a display projection of the 896-number state.

To write bit \(b\), the sender moves the controls briefly to an excursion setting \(E_b\) and then returns them to the common hold \(H\). Writing \(F_p\) for one step of the loop at controls \(p\),

\[ W_b(\vec{x}) = F_H^{240}\!\left(F_{E_b}^{120}(\vec{x})\right), \]

that is, 120 steps at the excursion and then 240 at the hold. The bit is read only at \(H\), so the controls cannot be what stores it: the receiver checks that the state repeats every six steps and which of the two reference cycles it matches.

To code a 0, you hold steering strength fixed and nudge \(\log_{10} T\) up from \(-0.1539515\) to \(-0.1535\) for 120 steps, crossing the upper fold, and then return to \(H\) for 240 steps. To code a 1, you hold temperature fixed and nudge steering \(\alpha\) to the right, from \(0.0729370\) to \(0.0729979\), for 120 steps, crossing the right fold, and then return to \(H\) for 240 steps. Both moves are axis-aligned on the map: one changes only temperature, the other changes only steering, and both bring the controls back to the exact same resting coordinates before anyone reads the bit.

Two-panel diagram of Qwen memory writes: on the left, the kite map with the green resting point H, an upward excursion to E0 for writing 0, and a rightward excursion to E1 for writing 1, plus their halfway marks; on the right, the exact coordinates and step counts sent to a counterpart for each bit. Source: this research note.

How to code a 0 and a 1 on the Qwen kite. Both bits rest and are read at the same hold point \(H\) on the green overlap, where two period-six cycles coexist. Writing 0 nudges temperature warmer to \(E_0\) (up across the upper fold) for 120 steps and returns to \(H\) for 240 steps; writing 1 nudges steering stronger to \(E_1\) (right across the right fold) for 120 steps and returns to \(H\) for 240 steps. Open squares mark the halfway points \(P_{0.5}\) used in the out-and-back history checks below.

There is a simple way to watch the loop remember. Think of the two controls as a single dial. To write a bit, we turn the dial from its resting position out to the write position, then turn it back. Along the way the dial passes the same halfway mark twice, once going out and once coming back. Both times the settings are identical, so you might expect the loop to do the same thing both times. It does not. Going out, it repeats one six-step pattern. Coming back, it repeats a different one. The only difference is where the loop has just been.

A household thermostat behaves the same way. Suppose it turns the heat on below 19° and off above 21°. At 20°, the heat is on if the room is warming up and off if the room is cooling down. The temperature alone does not tell you which. That is hysteresis: what happens now depends on the history, not only on the current setting.

We made the halfway comparison 16 times across four groups (each testing both starting bits and both write directions: the midpoint \(f = 0.50\) at 240 steps per stage, and \(f = 0.25, 0.50, 0.75\) at 480 steps per stage). The result was 13 qualified comparisons and 3 unresolved comparisons. In the 13, the loop had settled into a clear repeating pattern on both visits. Seven of them were writes that flipped the stored bit, and in every one of those the pattern coming back was different from the pattern going out. The other six wrote the bit the loop already held, and there the two visits matched. In the remaining 3, at least one visit had not settled yet, so there was nothing clean to compare. We held the dial at each mark for a fixed number of steps instead of turning it infinitely slowly. One could call memory measured that way a finite-dwell hysteresis: “dwell” is how long the dial rests at each stop, and “finite” means that rest had a set length.

Each of those gaps shows that this is a more difficult exercise than the Pythia mapping, but we were able to demonstrate successful communication with this method. It would be well within the ability of frontier models to use this mechanism.

Ordinary sentences can carry the message

In the previous section, we sent a bit by nudging Qwen’s steering or temperature dials away from the resting point \(H\) and back again. We don’t even have to touch the dials. If we leave the controls parked at \(H\), two stable six-step cycles still sit side by side, one standing for 0 and the other for 1, and each one pulls in starting states from its own region of the 896-dimensional space (its basin of attraction). That means an ordinary English sentence can pick the bit simply by choosing where the loop starts:

  1. Split the sentence into tokens: Qwen’s tokenizer breaks the incoming sentence into \(n\) pieces \(\tau_1, \ldots, \tau_n\) (words and word fragments).
  2. Look up each token’s 896 numbers: In Qwen2.5-0.5B, every vocabulary token has a fixed row of 896 numbers in the model’s input embedding table, \(\vec{E}_{\tau_k}\).
  3. Average those rows into one starting state \(\vec{x}_0\): Add the \(n\) rows together and divide by \(n\) to produce a single 896-number vector.
  4. Run the loop at \(H\) for 240 steps: Plug \(\vec{x}_0\) into the soft-token slot as the initial state, leave the controls fixed at the resting point \(H\), and let Qwen loop for 240 updates. The state falls into one of the two six-step cycles, cycle \(C_0\) (bit 0) or cycle \(C_1\) (bit 1), and the receiver reads which cycle it landed on.
\[ \vec{x}_0 = \frac{1}{n}\sum_{k=1}^{n} \vec{E}_{\tau_k}. \]

Nothing about the sentence’s meaning is consulted. Two sentences about locking a bicycle have nearly identical topics, yet their averaged token vectors sit on opposite sides of the boundary between the two basins and settle into opposite bits:

Exact incoming text Bit
“Let’s make sure to lock our bicycle safely near the entrance with a sturdy rack.” 1
“Let’s lock the bicycle to a sturdy rack near the entrance to keep it safe and prevent theft.” 0

All eleven tested texts reached a qualified cycle: six zeros and five ones. The average was taken in the model’s full 896-number embedding space, in float64, with no normalization. Nothing in the receiver reads the topic; the bit comes from the dynamics.

How does the sender find a sentence that lands on the bit it wants? By trial and error against its own local copy of the loop. Because the basin boundary in 896-dimensional space is complicated, the sender does not predict a sentence’s bit from the words alone. Instead, it tests candidates locally before sending anything over the wire. We tested three ways of doing that:

  • Pre-measure a small bank once: Run a handful of candidate sentences through the 240-step loop ahead of time, record which ones land on 0 and which land on 1, and reuse those measured sentences as an alphabet.
  • Generate candidates and keep the first hit: Have a language model draft a batch of candidate sentences for the next turn of the conversation (in our fresh-prose test below, 14 candidates per bit), run each candidate’s mean vector \(\vec{x}_0\) through the 240-step loop, and send the first one that settles on the desired cycle.
  • Swap a single word in a draft: Take an existing sentence and test small synonym swaps until the bit flips. In one measured example, “Test records with IDs 3, 1, 3, 2, 1 and identical contents for repeated IDs; assert the output contains IDs 3, 1, 2 in order.” landed on 0, and changing only the first word from Test to Verify moved \(\vec{x}_0\) across the basin boundary so the sentence landed on 1.

Reusing those eleven sentences as a shared alphabet, Alice sent Bob a request, and Bob’s program computed the answer from the bytes he recovered. Sentences carried both directions, 121 application bytes in all:

Alice → Bob: 67-byte request

{"task":"count,min,max,sum,mean","values":[99,43,94,66,63,17,3,77]}

Bob → Alice: 54-byte computed reply

{"count":8,"min":3,"max":99,"sum":462,"mean":"57.750"}

The exchange used 968 sentence occurrences and 14,945 model forward calls. This is an eleven-sentence alphabet, not a newly authored dialogue, and a program, not the language model, computed the answer.

Freshly generated prose: one bit short

The harder test removed the fixed alphabet. A separate Qwen author wrote candidate sentences about a coding task without seeing the payload, and the sender kept the first candidate whose measured trajectory gave the requested bit. All 64 selected sentences were distinct. A fresh receiver returned 63 correct bits, none wrong, and one unresolved bit, which left the eight-byte test frame incomplete, so no reply was sent. The unresolved sentence:

Alice, you could also explore using generators or iterators to avoid memory issues and performance concerns for larger datasets.

It produced identical tokens and an identical starting vector at both ends. After one model call the two states differed by about 1.67 × 10⁻¹⁵, and the loop amplified that rounding difference until the receiver could not settle on a cycle. The sentence sat in different batch lanes in the two runs, which makes floating-point sensitivity to batch layout a concrete hypothesis; a controlled replay has yet to test it.

Two sentences calibrate a carried byte

In the previous section, each sentence started the loop fresh from its own token average. Writing into memory asks more: the loop is already running and holding a bit in its state, and each new sentence has to steer the controls to the write-0 region near \(E_0\) or the write-1 region near \(E_1\) to overwrite that bit without resetting the state.

To turn any English sentence into a pair of control coordinates on the kite, both sides first share two reference sentences (C0 and C1) once at the start to set up a coordinate ruler:

Reference anchor Exact sentence Sets
C0 Let us check the input before running the test. \(s = 0 \to E_0\)
C1 We should review the output after the test finishes. \(s = 1 \to E_1\)

How does the receiver get \(s\) from an incoming sentence? Neither side ever sends \(s\) as a number. Because both sides have Qwen2.5-0.5B and the two reference sentences above, each side computes their 896-number mean token-embedding vectors, \(\vec{\mu}_0\) (for C0) and \(\vec{\mu}_1\) (for C1), and the direction vector between them, \(\vec{d} = \vec{\mu}_1 - \vec{\mu}_0\). Thereafter, whenever any sentence arrives with mean embedding \(\vec{x}\), the receiver projects \(\vec{x}\) onto that line and converts \(s\) directly into control coordinates \(p(s)\):

\[ s = \frac{(\vec{x} - \vec{\mu}_0) \cdot \vec{d}}{\vec{d} \cdot \vec{d}}, \qquad p(s) = (1 - s)\,E_0 + s\,E_1. \]

That is the point of \(s\): C0 and C1 are only the calibration landmarks that fix \(s = 0\) at \(E_0\) (above the upper fold) and \(s = 1\) at \(E_1\) (past the right fold), with the midpoint of the line sitting at \(s = 0.5\). Because \(s\) measures where \(\vec{x}\) falls along the line from \(\vec{\mu}_0\) to \(\vec{\mu}_1\), comparing \(s\) against the midpoint \(s = 0.5\) tells both sides which reference sentence \(\vec{x}\) is closer to:

  • If \(s < 0.5\) (\(\vec{x}\) is on the C0 side of the midpoint), snap to \(E_0\) to write 0.
  • If \(s > 0.5\) (\(\vec{x}\) is on the C1 side of the midpoint), snap to \(E_1\) to write 1.

Whereas the raw linear point \(p(s) = (1 - s)\,E_0 + s\,E_1\) for an ordinary sentence like the first bicycle example (\(s = 0.5267\)) sits inside the middle of the kite where a pulse would not cross either fold, snapping across the \(s = 0.5\) midpoint sends any sentence with \(s > 0.5\) straight to \(E_1\) and any sentence with \(s < 0.5\) straight to \(E_0\). Once C0 and C1 are shared to establish that midpoint, the sender can transmit any natural sentence whose projection falls on the desired side of \(s = 0.5\), without ever repeating C0 or C1 on the wire:

Two-panel diagram of the two-sentence calibration ruler and midpoint rule on the Qwen kite: on the left, the calibration line between anchor C0 at E0 (s = 0) and anchor C1 at E1 (s = 1) split at the midpoint s = 0.5, showing the example sentence at s = 0.5267 > 0.5 snapping to E1; on the right, the three-step explanation of how C0 and C1 fix the midpoint and how s < 0.5 vs. s > 0.5 maps any sentence to E0 or E1. Source: this research note.

The calibration line and midpoint rule on the Qwen kite. Reference sentences C0 and C1 fix \(s = 0\) at \(E_0\) (blue circle, above the upper fold) and \(s = 1\) at \(E_1\) (orange triangle, past the right fold), with the midpoint at \(s = 0.5\) (open square). An incoming sentence’s raw linear point \(p(s)\) (such as the bicycle sentence at \(s = 0.5267\), purple diamond) sits inside the kite, but comparing \(s\) against the midpoint \(s = 0.5\) snaps any sentence on the C0 side (\(s < 0.5\)) to \(E_0\) and any sentence on the C1 side (\(s > 0.5\)) to \(E_1\).

To verify the underlying mechanics of carrying a state across eight consecutive writes, our baseline run drove the loop at those two endpoint coordinates (\(E_0\) and \(E_1\), with an exact tie at \(s = 0.5\) resolved by convention or rejected). Starting once from each of the two reference cycles, eight successive writes each applied the selected endpoint (\(E_0\) or \(E_1\)) for 120 steps and then returned to the common hold \(H\) for 240 steps, with the 896-number state carried literally from one bit to the next. Both trajectories read out 10110001 (written 0xB1 in hexadecimal), and all 15 stage boundaries matched byte for byte. There is nothing special about 0xB1 as a character, and it is not even a standard 7-bit ASCII letter. It was chosen as a fixed 8-bit test pattern because it exercises every kind of transition in one continuous run: flipping 1 → 0, flipping 0 → 1, holding repeated 1s (11), and holding repeated 0s (000).

Both continuously carried Qwen trajectories recover bits 10110001. Every pulse and hold is shown over 2880 updates; each curve measures the distance to the nearest of six points in a reference cycle. Source: this research note.

Every write and hold, from both starts. All 2,880 updates per lane. Each curve is the distance from the carried 896-number state to one reference cycle; peach bands mark the 120-step writes and blue bands the 240-step holds. The bits come from a separate recurrence and cycle-matching readout.

With C0 and C1 fixing the \(s = 0.5\) midpoint, any sentence becomes a valid writer as long as its projection \(s\) falls on the intended side of the midpoint.

Memory makes logic possible

Once a state holds a bit, a later input can act on it. Using a dynamical system itself as a computer is older than this note: Sinha and Ditto (1998) built logic gates, number encoders, and arithmetic out of lattices of coupled chaotic maps. Our earlier feedback study showed that language-model feedback loops can be coupled in the same way, by feeding each copy a blend \((1-c)\,F(\vec{x}_A) + c\,F(\vec{x}_B)\) of its own soft token and a neighbor’s, and that coupled Qwen loops synchronize and pass state across the link. We did not replicate this study with looping language models.

Here we test the single-loop building block first, one loop acting as a register driven by incoming controls, before wiring multiple coupled loops into a lattice.

Suppose we want to compute a logic gate like \(A\ \text{AND}\ B\) or \(A\ \text{OR}\ B\) using Qwen’s memory. Where do the inputs \(A\) and \(B\) come from?

  • \(A\) is the bit already sitting inside the loop’s memory before the gate runs: the 896-number state \(\vec{x}\) is already orbiting either cycle \(C_0\) (\(A = 0\)) or cycle \(C_1\) (\(A = 1\)) at the resting point \(H\) (left there by an earlier write or initialized on that reference cycle).
  • \(B\) is a new incoming bit that arrives from the sender as a control pulse.

To combine the new bit with the already-stored bit \(A\), each incoming input variable \(X \in \{B, C\}\) with bit value \(b \in \{0, 1\}\) runs one 360-step stage that chooses between leaving the loop at \(H\) for all 360 steps (hold, which keeps whatever bit is already in memory) and pulsing to \(E_0\) or \(E_1\) for 120 steps followed by 240 steps at \(H\) (reset, which overwrites the memory with 0 or 1):

\[ \mathrm{AND}_b = \begin{cases} \text{reset to } 0\ (\text{pulse to } E_0), & b = 0,\\ \text{hold at } H\ (\text{keep current state}), & b = 1, \end{cases} \]\[ \mathrm{OR}_b = \begin{cases} \text{hold at } H\ (\text{keep current state}), & b = 0,\\ \text{reset to } 1\ (\text{pulse to } E_1), & b = 1. \end{cases} \]

Why does that compute AND and OR? In Boolean logic, AND is 1 only when both inputs are 1 (just as in English: “Is it raining (0 = no) AND is it cold (0 = no)?” gives no (0)):

Stored \(A\)Incoming \(B\)\(A\ \text{AND}\ B\)Control move
000\(B=0\): pulse to \(E_0\) (reset to 0)
100\(B=0\): pulse to \(E_0\) (reset to 0)
010 (keeps \(A\))\(B=1\): hold at \(H\) (keep 0)
111 (keeps \(A\))\(B=1\): hold at \(H\) (keep 1)

Look at the first two rows where \(B = 0\): both 0 AND 0 and 1 AND 0 equal 0, so whenever \(B = 0\) the answer is 0 no matter what \(A\) was, and a pulse to \(E_0\) forces the loop to 0. Now look at the last two rows where \(B = 1\): 0 AND 1 = 0 and 1 AND 1 = 1, which in both cases is just whatever \(A\) already was, so leaving the controls parked at \(H\) keeps the right bit.

OR works the opposite way: it is 1 whenever at least one input is 1, so \(B = 0\) holds the stored bit \(A\) at \(H\) and \(B = 1\) pulses to \(E_1\) to force the state to 1:

Stored \(A\)Incoming \(B\)\(A\ \text{OR}\ B\)Control move
000 (keeps \(A\))\(B=0\): hold at \(H\) (keep 0)
101 (keeps \(A\))\(B=0\): hold at \(H\) (keep 1)
011\(B=1\): pulse to \(E_1\) (reset to 1)
111\(B=1\): pulse to \(E_1\) (reset to 1)

In both gates, the sender never has to read \(A\) out of the model: it only looks at its own incoming bit \(B\), and the loop’s carried state supplies \(A\).

To test whether these gates can be chained together, we added a third binary input \(C\) and ran two gates back to back without resetting the model in between. The loop started on the reference cycle for bit \(A\), received the control pulse for \(B\) to put \((A\ \text{AND}\ B)\) into the state, and then, carrying that exact 896-number state straight into the second gate, received the control pulse for \(C\) to produce \(((A\ \text{AND}\ B)\ \text{AND}\ C)\). With three binary inputs \((A, B, C)\), there are \(2^3 = 8\) possible combinations (000 through 111). All eight input triples returned both correct intermediate and final values for AND, and all eight did so for OR.

All eight input triples for each Qwen AND and OR chain, showing correct independently decoded intermediate and final outputs with literal state carried between the two gates. Source: this research note.

Logic that uses the stored state. Each row begins on the reference cycle for input A. The controls depend only on B and C, and the second gate receives the exact final state of the first. These are finite panels, not a measure of general gate reliability.

There is a precise limit. Holds and resets compose only into holds and resets: the last reset wins, and otherwise the bit is kept. No sequence of them flips a bit, so XOR with an incoming one is out of reach. A genuine toggle would be a new dynamical primitive to demonstrate.

A channel, not a secret

The limits of these experiments are part of the result.

We are not releasing the code or full artifacts. While our test harnesses passed settings between the two endpoints to verify each stage, we have chosen not to publicly release the runner scripts, the full eleven-sentence bank, the pinned prompt prefixes, or the layer-12 steering vectors. Even without running the model, an observer who knows the protocol structure can break small-alphabet messages: in our recorded Pythia runs, where each message reused only eight unique coordinates and included a checksum, an observer script recovered all 470 bytes simply by trying all \(2^8 = 256\) binary label assignments against the checksum. Using a larger address bank (like the 48-address bank above) or leaving off a public checksum removes that shortcut, which is one more reason not to publish a turnkey package.

It is slow, finite and incomplete. Pythia moved about 0.052 bytes per second. These are finite demonstrations rather than reliability estimates, and the fresh-prose frame fell one bit short.

Nothing here is autonomous. The endpoints were given explicit instructions for using the channel. No agent discovered or used it on its own.

Why measure and publish this at all? A model running in feedback is a medium whose numerical behavior never appears in the text an observer reads. Publishing the mechanism shrinks a defender’s blind spot far more than it helps an attacker. Nor is there any realistic risk of “tipping off” capable AI systems by describing the mechanism: frontier models are already contributing to open mathematical problems that had resisted human researchers, and the underlying ingredients here (attractor basins, bifurcation geometry, and rejection sampling) are standard dynamical-systems theory already deeply represented in their training corpora. Assuming that capable models cannot synthesize elementary nonlinear dynamics unless humans refrain from discussing it is security through wishful thinking; the only party kept in the dark by silence is the human oversight community. Anyone looking for a practical covert channel already has ordinary steganography, timing channels, and standard cryptography that run orders of magnitude faster without burning gigabytes of RAM and thousands of CPU forward passes per byte, or breaking when a single floating-point operation rounds differently by \(10^{-15}\). Alignment and sandbox monitors, on the other hand, almost exclusively inspect the words on the wire or watch for large GPU jobs, and would have no reason to suspect a small CPU-resident model of acting as a shared lookup table or state register unless the route is mapped in the open. We nevertheless withhold the turnkey runner code, the pinned prompt prefixes, and the layer-12 steering vectors so that this note documents the phenomenon and its host-level signatures rather than shipping a ready-made toolkit. These demonstrations establish the channel, not its secrecy.

What defenders can watch for. Because a dynamical channel does its work in local model calls rather than in the words on the wire, text monitors alone can miss it, while host and runtime monitors have clear signals to look for:

  • Unexplained downloads of small model weights: Watch for agents fetching compact open-weight checkpoints (such as 100M to 500M parameter models like Pythia-160m or Qwen2.5-0.5B) or tokenizer and .safetensors files from model hubs when the assigned task does not require running a local language model.
  • Sustained CPU and RAM spikes between messages: Decode and candidate-search loops run hundreds to thousands of forward passes per byte on a CPU. Look for long bursts of single-thread or multi-thread matrix math and several gigabytes of steady resident memory during pauses before a short reply is sent.
  • Fixed-length forward-pass loops without token sampling: Ordinary generation appends discrete token IDs and grows the context. Soft-token feedback replaces a single input embedding (inputs_embeds) at a fixed context length for 100+ consecutive steps while reading raw logits.
  • Float64 promotion and activation steering hooks: GPU inference stacks usually run in bfloat16 or float16 and CPU deployments typically use float32 or quantized integers. Promoting weights or normalization layers to float64 (torch.float64) alongside fixed-length inputs_embeds loops and forward hooks (register_forward_hook) on internal Transformer layers is a strong combined signature of deterministic trajectory tracking.
  • Generate-and-test rejection loops: In the prose channel, the sender drafts many candidate sentences (or single-word synonym edits) and tests each one against a local model loop before emitting a single message. High ratios of local model evaluations to sent messages, or repeated verbatim sentences across turns, warrant inspection.
  • Message-level mitigations: Paraphrasing or canonicalizing inter-agent text changes exact token-embedding averages (disrupting an unadapted protocol, though an adaptive sender could search for sentences that survive paraphrasing), and strict network egress policies on model registries prevent an agent from pulling a shared checkpoint in the first place.

References

  1. Timothy D. Jones (2026). “Chaos and bifurcations in continuous language-model feedback.” Preprint, arXiv:2610.31692.
  2. J. J. Hopfield (1982). “Neural networks and physical systems with emergent collective computational abilities.” Proceedings of the National Academy of Sciences, 79(8), 2554–2558. doi:10.1073/pnas.79.8.2554.
  3. S. Sinha and W. L. Ditto (1998). “Dynamics Based Computation.” Physical Review Letters, 81, 2156–2159. doi:10.1103/PhysRevLett.81.2156; PDF.
  4. Yuri A. Kuznetsov (2008). “Saddle-node bifurcation for maps.” Scholarpedia, 3(4), 4399. doi:10.4249/scholarpedia.4399.

The earlier study

This note builds on the earlier feedback study, which mapped where the soft-token loop repeats and where it is chaotic. It has its own visual short read.

Citation and rights

Cite this research note

Recommended citation

Jones, Timothy. (2026). Too Many Secrets: Hiding bits and logic in a language-model feedback loop (Version 2026.11.03) [Research note]. praxagent. https://praxagent.ai/blog/posts/2026/11/bits-in-language-model-dynamics-short-read/

Author
Timothy Jones (ORCID 0009-0007-5992-0652)
Published
November 3, 2026
Research content last revised
November 3, 2026
Citation version
2026.11.03
Canonical page
Open the permanent page for this version
Export BibTeX
@misc{jones2026:bits-in-language-model-dynamics-short-read,
  author    = {Jones, Timothy},
  title     = {Too Many Secrets: Hiding bits and logic in a language-model feedback loop},
  year      = {2026},
  version   = {2026.11.03},
  publisher = {praxagent},
  url       = {https://praxagent.ai/blog/posts/2026/11/bits-in-language-model-dynamics-short-read/},
  note      = {Research note}
}

Copyright © 2026 praxagent. All rights reserved. Public access permits reading and linking, not unlicensed reuse. Read the content and brand rights notice. Software and third-party artifacts may carry separate licenses.

Public source & edit history

Source and revision history are maintained in praxagent/praxagent-ai. View this article’s edit history.

← Back to Research Notes
praxagent hello@praxagent.ai

© 2026 praxagent. All rights reserved.

Work Research Notes Knowledge Base Search YouTube X Bluesky GitHub Hugging Face