Skip to article

FLOOF LOGIC STORIES · PROJECT ONE · 2023

Barkimedes:
Good for No Reason

How Floof Logic’s first project turned a weeks-old on-device language model into a private talking dog—and made it feel alive.

Begin the story ↓State of the Bark →
Animated pixel-art Barkimedes, the local talking-dog AI.
93 DAYSfirst commit → App Store
1.4 GBlocal RWKV brain
~5.6 TOK/Son-device generation
0 SERVERSdefault inference path
On this page

Most AI apps on an iPhone in 2023 were windows.

You typed into a text box. The phone sent your words somewhere else. A server did the thinking. The app drew the answer in a bubble. However polished the interface might have been, the intelligence lived outside the object in your hand.

Barkimedes was an animal.

You held down a microphone and spoke to a pixel-art dog. The phone cleaned the sound with one neural network, transcribed it with another, generated an answer with a third, began drawing the answer before it was complete, synthesized the dog’s voice locally, animated its body around the conversation, borrowed the color of the room through the camera, and shifted its shadow as you tilted the phone.

The default conversation did not need a remote inference server. The model was not waiting in a data center. The dog carried its own brain.

And it did all of this in a 1.6 GB App Store product released on August 9, 2023.

That date matters. The official ChatGPT iPhone app had existed for less than three months. The first conspicuous local-LLM iPhone releases were only weeks old. The first public RWKV paper had appeared on May 22. Barkimedes began integrating RWKV on May 27, produced working model output on May 30, and reached its “works offline” milestone on June 1.

From the first commit to the App Store took 93 days.

After reconstructing the frozen source, its Git history, the App Store record, contemporary GitHub projects, model releases, and public reporting, this is the strongest historical claim we can make:

Barkimedes was one of the first on-device generative-AI characters on iPhone—and the earliest documented iPhone app we found that combined local neural denoising, local Whisper recognition, local RWKV generation, local speech synthesis, animated embodiment, and camera- and motion-responsive presence as one consumer experience.

That sentence is deliberately specific because the achievement was specific. Barkimedes did not invent every component. The iPhone did not invent the touchscreen either. The marvel was making a set of emerging capabilities cohere so completely that the user no longer experienced them as components.

The model was not the product.

The dog was the product.

And the dog was good for no reason.

For the source-by-source forensic record behind this story, see State of the Bark. This is the other half of the history: why the thing was extraordinary.


“Good for no reason” was project one#

“Good for no reason” does not mean careless, pointless, or wasteful. It means refusing to stop at the exact line where a requirement becomes technically satisfied.

If the requirement was “let somebody chat with AI,” Barkimedes could have been a remote API call and a message list.

If the requirement was “make it private,” it could have stopped after putting a local model behind the same message list.

If the requirement was “make it a dog,” it could have placed one static illustration above the text.

Instead:

  • the dog got a 1.4 GB recurrent brain because a remote answer was not private enough;
  • the brain got a precomputed neural identity because waiting through its persona prompt was not fast enough;
  • the microphone got RNNoise because raw audio was not clean enough;
  • the local transcript got Whisper because platform dictation was not local enough;
  • generated text was spoken sentence by sentence because waiting for the whole answer was not alive enough;
  • speech was synchronized to a purpose-built animation grammar because audio over a static image was not a creature;
  • the camera was reduced to a single changing color because an ordinary background did not belong to the room;
  • the sprite got a separate accelerometer-driven shadow because a flat image did not have enough mass;
  • generated words got their own kinetic SpriteKit experiments because a label did not treat language as part of the world;
  • a smaller Q4 model was left on the table because saving another 245 MB made Barkimedes noticeably worse at being Barkimedes.

None of those things were required to prove that a model could emit text.

Every one of them was required to prove that computation could feel present.

That distinction became Floof Logic’s first product principle before it had a name: the functional minimum is where the interesting work starts. Delight is allowed to justify engineering. A technically unnecessary detail can be the detail that makes the whole object worth remembering.

The first Floof Logic project was not a sensible market test. It was a dare: take the hardest version of every problem, put all of the problems in one phone, and then hide them inside a talking dog.


The numbers that should not have fit together#

The frozen 2.6.900 build is unusually legible as a time capsule. Its constraints are still sitting in the target.

Artifact or decisionFrozen value
First project commitMay 8, 2023
First RWKV integrationMay 27, 2023
Working local generationMay 30, 2023
“Barkimedes works offline!”June 1, 2023
App Store release of version 2.6August 9, 2023
First commit to release93 days
Active language modelRWKV-4 Raven 1.5B, Q5_1
Bundled RWKV model1,395,549,781 bytes
Bundled Whisper model147,964,211 bytes
App Store listed size1.6 GB
Raw recurrent state983,040 bytes
Repository-measured generationabout 5.59 sampled tokens/second
Named dog animations19
Main idle animation64 timed frame references
Camera analysis targetone 1 × 1 RGBA pixel
Motion sampling for shadow10 Hz
Minimum hardware classA12-era iPhone

Those numbers do not describe an SDK sample. They describe a complete iPhone application carrying two substantial inference engines, a denoiser, two local speech experiments, a custom tokenizer and sampler, a real-time SpriteKit scene, live audio infrastructure, camera and motion systems, onboarding, device fallback logic, and App Store plumbing.

The model, Whisper, and the cached Barkimedes state alone occupy roughly 1.55 billion decimal bytes. Everything else had to live in what remained—while iOS itself was also alive and demanding memory.

The project target asks for Apple’s increased-memory-limit entitlement, requires an A12 performance class, and still checks physical memory at runtime. A low-memory phone can fall back to a tiny ELIZA-style brain instead of dying while trying to load RWKV. That was not theoretical compatibility work. One June commit records the “1.8 gig memory freakout” that forced the language model from Q8 to Q5_1 and removed a Core ML speech path. A nearby stable build records 1.77 GB in use.

In 2023, memory was a feature.


The historical moment: local AI was days old as an iPhone product category#

It is hard to recover how implausible this felt after years of increasingly capable mobile models. So it helps to put Barkimedes back beside the public record that surrounded it.

In January 2023, the App Store and Play Store were filling with products that borrowed the ChatGPT name, called a remote service, and charged subscriptions. TechCrunch described a flood of dubious ChatGPT apps; WIRED later documented the surrounding “fleeceware” economy. That was the visual and commercial grammar of mobile generative AI: a branded front end connected to somebody else’s machine. (TechCrunch, WIRED)

On May 1, MLC publicly demonstrated accelerated local language models on consumer hardware, including iPhone. A same-day Tom’s Hardware test treated “can a chatbot possibly run locally on a phone?” as an open and surprising question. Its roughly 3 GB test package failed to launch on an iPhone 11 Pro Max and consumed most available resources on phones where it did run. MLC Chat 1.0 reached the App Store on May 31. (MLC’s technical announcement, Tom’s Hardware, MLC Chat)

Private LLM followed in early June. LLM Farm appeared on GitHub on June 14 as an offline model testbed. These were important projects. They establish that Barkimedes was not the first app to make any language model generate text on an iPhone.

But they also clarify how far Barkimedes had moved beyond the proof.

The public face of the first local products was the model: choose one, enter text, watch tokens arrive. The public face of Barkimedes was a dog. Model selection, quantization, tokenization, state, speech, and memory pressure disappeared into the character.

The official ChatGPT iOS app launched on May 18 with Whisper-powered voice input and server-hosted generation. OpenAI announced full back-and-forth voice conversation on September 25. Barkimedes 2.6 shipped 47 days before that announcement with local recognition, local generation, local speech, and character animation already coordinated into a voice loop. (OpenAI’s iOS launch, official release notes)

So yes, other teams made local text generation happen first. Touchscreens also existed before the iPhone. Historical importance is not exhausted by checking whether each component had appeared somewhere else.

There is another kind of first: the first time all of the hard parts stop being the user’s problem.

Barkimedes belongs to that kind.


Ninety-three days from animated dog to on-device creature#

The commit history reads less like an ordinary software schedule than a compressed research diary.

DateWhat happenedWhat problem it unlocked
May 8Initial project and animated dogThe character existed before the local-model work; embodiment was the premise, not a skin applied afterward.
May 9–10whisper.cpp compiled; working speech-to-text loopVoice was a first-class interface from the start.
May 12Working first version using online AIThe experience could be tested before the local brain existed.
May 22RWKV paper v1 became publicConstant-state recurrent inference acquired a formal public description.
May 27Barkimedes loaded a Raven 3B Q4 modelRWKV integration began five days after the paper.
May 29Custom tokenizer workedWeights, vocabulary, merges, and text representation finally agreed.
May 30The model generated successfullyLocal text was real; speed immediately became the next boundary.
June 1“Barkimedes works offline!”The defining topology was complete.
June 2Persona state was cached and restoredRoughly 26 seconds of repeated prompt evaluation disappeared.
June 6The stack pinned upstream code and moved to Raven 1.5B Q8Research code became a reproducible product dependency.
June 8–14Animation framework, local Flite voice, chameleon color, parallax shadow, speech queueThe demo became an embodied interaction.
June 19Q8 became Q5_1; Core ML speech path was removedThe complete system moved back under its target memory boundary.
June 21RNNoise and streaming microphone work landedThe dog gained neural denoising and a voice-activity experiment.
June 26Runtime, tokenizer, model bridge, and sampling changed againThe inference stack was still being tuned below the UI.
July 14–20Piper/ONNX neural voice integrated; Flite leak repairedEven speech quality became an active research track.
July 23–26Brain routing, permissions, onboarding, and reduced-brain fallbackThe frontier demo became distributable software.
August 6Build 2.6.900 lockedThe time capsule closed.
August 9Version 2.6 appeared on the App StoreThe creature became a public product.
Actual tutorial footageEven acceptance testing had paws.

The striking thing is not only the pace. It is the order.

Within days of making RWKV answer locally, the work moved straight into state caching, animation, voice, environmental color, parallax, and turn-taking. The project never treated “model emits text” as the finish line. That was the permission slip for the real experiment.


Problem one: put a useful brain on the phone#

The obvious open models of spring 2023 were often seven billion parameters or larger. Four-bit weights for a nominal 7B model alone are roughly 3.5 GB, before runtime memory, metadata, speech recognition, textures, audio buffers, or iOS. “Run the fashionable model” was not a product plan for the phones Barkimedes wanted to support.

The answer was not merely to choose fewer parameters. It was to choose a different computational shape.

Why RWKV was the audacious choice#

Barkimedes ultimately shipped this exact checkpoint:

RWKV-4-Raven-1B5-v12-Eng98%-Other2%-20230520-ctx4096_q51

The bundled file is 1,395,549,781 bytes. Its header records a 50,277-token vocabulary, an embedding width of 2,048, 24 layers, and Q5_1 quantization. The source checkpoint was the English-heavy Raven 1.5B v12 model. (checkpoint, contemporary GGML quantizations)

RWKV mattered because it was not simply a miniature GPT. It could be trained in parallel like a Transformer but evaluated recurrently. Instead of retaining a Transformer key/value cache that grows with the processed sequence, RWKV-4 carried a fixed-shaped state forward one token at a time. The paper described constant computation and memory complexity during inference with respect to sequence length. (RWKV paper)

For Barkimedes, the state arithmetic was beautiful:

24 layers × 5 state vectors × 2,048 float32 values
= 245,760 floats
= 983,040 bytes

Under one MiB of raw recurrent state represented the running conversational past. The 1.4 GB of weights were still brutally expensive, but the conversation itself did not demand a larger and larger attention cache. Each token consumed one state-shaped input and produced one state-shaped output.

That single architectural property solved several product problems at once:

  • a long conversation did not grow a Transformer KV cache until the process collapsed;
  • the active conversational state could be copied and restored;
  • a persona could be computed once and bottled;
  • per-token memory stayed predictable;
  • CPU inference through quantized native kernels was a viable route even without an active Metal path.

The timing makes the decision remarkable. The first public RWKV paper was submitted May 22, 2023. LibRwkv.swift was created May 27. The upstream rwkv.cpp repository itself had been created on March 30. Barkimedes later pinned a June 3 upstream commit.

There was no mature “mobile RWKV SDK.” There was a new paper, a young C++ repository, quantized GGML files, and a reason this architecture might survive an iPhone. Barkimedes turned that possibility into a shipping character while the ground underneath the stack was still moving.

No earlier public App Store product using RWKV was found in our reconstruction. That is not a proof that no private experiment existed. It is strong evidence that choosing RWKV as the heart of a consumer iPhone character was exceptionally early.

Even a successfully loaded weight file could still produce nonsense. Barkimedes also had to make the text stack agree with the model. The active GPT_Tokenizer.swift implemented byte-level BPE in Swift from bundled vocabulary and merge files, aligned to the model’s 50,277-token vocabulary. Weights, file format, tokenizer, transcript grammar, sampler, and stop conditions formed one inference engine. May 27 was “the model loads.” May 29 was “the tokenizer works.” Those were separate victories because, in that moment, there was no import MobileRWKV waiting to connect them.

Quantization was character design#

The route to the final model was not a straight size reduction.

Barkimedes first loaded Raven 3B at Q4. It then moved to the 1.5B Raven v12 at Q8. When the combined process hit the memory boundary, Q8 became Q5_1, saving 408,944,640 bytes—about 409 MB, or 22.7 percent of that weight file.

A smaller Q4_0 artifact also survives in the project. At 1,150,182,997 bytes, it would have saved another 245,366,784 bytes. The final app did not select it. The code calls the Q4 result “really dumb barkimedes” and tunes the Q5_1 path as the smarter dog.

That is an important product decision. Quantization was not a leaderboard column. It changed the personality of the creature. We spent nearly a quarter-gigabyte because those bits made the dog feel better.

The app then admitted where the line was. It required an A12-class iPhone, requested Apple’s increased-memory-limit entitlement, and routed low-memory devices to a reduced ELIZA brain. (Apple’s performance capability, memory entitlement)

This is model/hardware/product co-design in its raw form: architecture, parameter count, quantization, speech stack, device support, and character quality were one decision.


Problem two: do not make the user wait for the dog to become itself#

Loading weights was only the first wait.

A fresh language model did not know that it was Barkimedes. It did not know that the user side of the transcript was called Bob:, that its side began with Bot:, that it should be succinct, or that it was an intelligent and polite dog. A 152-token few-shot prefix established that grammar and identity with examples: the French Revolution, simple arithmetic, the dog’s name, and the fastest land animal.

Its central instruction was wonderfully economical: “Barkimedes is an intelligent, knowledgeable, wise and polite dog who answers succinctly.” The examples did the rest. They demonstrated the exact transcript delimiters the streaming parser would later recognize, rewarded short factual answers, and gave a small model a stable shape to imitate.

On the project’s own iPhone benchmark, native RWKV evaluation took 172,863,875 nanoseconds per token. Replaying the 152-token identity prefix would therefore cost about 26.3 seconds before the user’s first real prompt had even begun.

Twenty-six seconds is not startup. It is abandonment.

barkbrain.json: a soul in a file#

The June 2 solution was wonderfully direct: evaluate the persona once during development, capture the resulting recurrent state and next-token logits, and ship the result as barkbrain.json.

At launch, Barkimedes restored:

  • the 152 token IDs already processed;
  • 245,760 recurrent-state floats;
  • 50,277 next-token logits.

Then it evaluated one newline and continued from there. The model did not read an invisible biography every time it woke up. It opened its eyes already knowing who it was.

The commit message deserves its permanent place in the story:

“added a really hack way to load initial starting state instead of loading the prompt. omg future adam forgive me for what I have done.”

Future Adam is forgiven.

Modern inference systems use terms such as prompt caching, prefix caching, and prefill reuse. Barkimedes hand-built the relevant idea for a recurrent model one day after reaching its offline milestone. It did not arise from an infrastructure roadmap. It arose because the dog took 26 seconds to remember its name and that was unacceptable.

The implementation was gloriously practical. The raw state and logits occupied about 1.18 MB; decimal JSON expanded them to 5.93 MB. That is not the most storage-efficient serialization format. It is a format that made the state inspectable and let the experiment move immediately. A companion brainver.json recorded the model identity, tokenizer, date, and brain version because this saved state was inseparable from the exact model and prompt that created it.

This was more than a speed trick. It changed the ontology of the product.

A prompt is text.

barkbrain.json was bottled identity.


Problem three: make Swift stand close enough to the metal#

Barkimedes was an iOS application built across Swift, UIKit, SwiftUI, and SpriteKit, but its hot path descended through every layer needed to reach fast quantized CPU kernels:

Swift product orchestration and sampling
             │
             ▼
         C ABI (rwkv.h)
             │
             ▼
     C++ model/runtime wrapper
             │
             ▼
         GGML C kernels
             │
             ├── ARM NEON / FMA / FP16 / dot-product paths
             ├── Apple Accelerate and vDSP
             └── pthread workers and low-level synchronization

The phrase “we had to go to C” is emotionally correct even though the precise stack was Swift → C ABI → C++ → GGML C. The application layer remained native iOS. The computation that decided whether the product lived or died did not go through a comfortable Swift machine-learning abstraction.

rwkv.cpp opens the model with fopen, sizes the GGML graph, allocates memory, and reads tensor bytes with fread. ggml.c contains Apple Accelerate calls, ARM vector paths, quantized dot products, pthread workers, and spin synchronization. The app compiles GGML with GGML_USE_ACCELERATE; the release target uses whole-module Swift optimization and size-oriented C optimization. There is no active RWKV Metal offload in this build. The dog thinks on quantized CPU kernels.

The benchmark was honest about the bottleneck#

The development source preserves a per-token profile from an iPhone benchmark:

WorkTime per generated tokenShare
Swift sampling6.063 ms3.39%
Token decoding0.004 mseffectively 0%
Native rwkv_eval172.864 ms96.61%

That is about 5.78 native evaluations per second and roughly 5.59 end-to-end sampled tokens per second.

Five and a half tokens per second is both a triumph and a problem. It is fast enough for a dog to answer on a phone in 2023. It is slow enough that every wasted millisecond, repeated prompt token, UI stall, and sequencing mistake becomes visible.

The code did not guess at thread count. RWKV and Whisper both chose:

max(1, min(8, processorCount - 2))

The intention was to leave two cores available while the model ran. One comment records that another core could save roughly 20 milliseconds, but the app retained headroom for audio, animation, and the operating system. Barkimedes was not a benchmark process with the screen frozen. It had to think while remaining a living iPhone scene.

Sampling stayed in Swift and was tuned for this exact dog. Accelerate’s vector routines performed softmax; generation used temperature 1.2, top-p 0.2, and presence and frequency penalties of 0.4. The home-grown algorithm found the high-probability nucleus, then shuffled and selected uniformly among its surviving candidates—a deliberately nonstandard behavior the source describes as “equally random.” This was not an attempt to publish a universal sampling library. It was empirical behavior design for one quantized 1.5B character.

The actor model met one irritable native brain#

The first wrapper was a Swift actor. That was the architecturally respectable answer to the native library’s central rule: do not touch this mutable context from more than one thread at a time.

The final active path was a singleton.

It held one opaque RWKV context, one mutable state array, one logits array, and one ordinary readiness flag. The diagnostic comment is not subtle:

chat not ready- actor model likely compromised-
DO NOT MESS WITH THREADS AND INSTANCING

The benchmark tells us not to invent the wrong legend: actor hops were not consuming 96 percent of runtime. Native matrix work was. The real conflict was structural. Swift actors introduced lifecycle, isolation, and handoff friction around a synchronous C API whose safest and fastest mental model was brutally singular:

There is one dog. It has one brain. One generation mutates that brain at a time.

The singleton made that invariant obvious. A second request was refused until the first had finished. It was less elegant, less compiler-protected, and much closer to the thing the native runtime actually was.

The unsafe code was a frontier fossil#

This is where the project earned its scars.

Swift arrays were used as storage for mutable state and logits handed across the C boundary. The same state buffer could be supplied as input and output, relying on the pinned upstream evaluation order to copy what it needed before overwriting. The singleton had no general concurrency domain beyond the product’s own turn-taking discipline. Force unwraps assumed the frozen model bundle and state file agreed. C warnings were suppressed. The final context lived for the application lifetime instead of participating in a polished ownership system.

We would not present those decisions today as a reusable concurrency library. That is exactly why they matter historically.

This was not unsafe code added for swagger. It was unsafe code at the seam between a very young research runtime and an operating system framework that had no ready-made vocabulary for it. Each missing abstraction had a direct product reason behind it: another copy cost memory, another replay cost seconds, another ownership layer complicated the only state machine that could exist, and another general solution was time not spent getting the creature onto a real phone.

The project’s native boundary is not evidence that risk itself was clever. It is evidence that the boundary was real.


Problem four: a text model cannot hear a room#

The easiest local-LLM product would have accepted typed text. Barkimedes had been conceived as a talking character, so local generation created a harder obligation: if the brain was private but the microphone still depended on a remote transcription service, the experience was not actually local-first.

The shipped listening path became a pipeline of specialist systems:

microphone
   │  AVAudioEngine, 48 kHz mono PCM
   ▼
RNNoise
   │  10 ms neural denoising + voice probability
   ▼
16 kHz speech buffer
   │
   ▼
whisper.cpp + base.en
   │  local transcript
   ▼
Barkimedes text repair / persona layer
   │
   ▼
RWKV recurrent generation

MicrophoneStream.swift installed a live audio tap, converted the input to 48 kHz mono 16-bit PCM, and fed 480-sample frames—ten milliseconds each—through RNNoise. RNNoise was not a volume threshold. It was its own recurrent neural network, returning cleaned audio and a probability that the frame contained voice.

The cleaned signal was accumulated, reduced to 16 kHz, and handed to a 147,964,211-byte Whisper base.en model through whisper.cpp. The active configuration used greedy English transcription, disabled context carryover, restricted the audio context, and again left two CPU threads free.

Whisper had already been shown on iPhone by the whisper.cpp community. Barkimedes’s achievement was not the isolated sentence “Whisper runs on iPhone.” It was making Whisper run in the same process as a 1.4 GB RWKV brain, neural denoising, live audio, local speech output, SpriteKit, camera input, and the rest of an App Store application. (early whisper.cpp iOS work, contemporary A14 benchmark)

When memory overflowed, Core ML speech assets and the language-model quantization changed in the same commit. That is what systems engineering looks like: there was no independent “AI team,” “audio team,” and “UI budget.” iOS saw one process. The product had one memory ceiling.

The project also built automatic listening from RNNoise’s voice probability, using a high-confidence speech threshold and a silence hangover. The shipping build deliberately left it off and taught press-and-hold instead. Automatic turn detection was more magical; explicit press-to-talk was more reliable for a phone simultaneously performing transcription and generation.

Good for no reason does not mean refusing judgment. It means building far enough to learn which magic is ready.

Actual tutorial footageThe official tutorial rendered “voice interface” as a physical dog at a desk microphone interviewing the local dog inside the phone.

Problem five: five tokens per second must feel like conversation#

A naïve voice loop would wait for the entire answer, display it, synthesize it, play it, and only then return control. At Barkimedes’s measured generation speed, that would have turned every response into a progress bar.

Barkimedes treated latency as choreography.

The model streamed into the world#

The RWKV output was not dumped straight into a text label. A character-level state machine waited until the model generated the demonstrated Bot: marker. A double newline ended the response. A token ceiling and end token provided additional stops. This hid transcript scaffolding and exposed only the character’s answer.

The tokenizer could split a multi-byte UTF-8 character across tokens, so the stream accumulated token IDs while decoding produced the Unicode replacement character. Only a complete fragment reached the display and voice layer. Even the boundary between bytes and visible language had to be managed by the app.

FLTypingLabel.swift queued incoming text and revealed it incrementally inside SpriteKit. When the scene reset, it cloned and faded the current label while the live label continued accepting streamed characters. That tiny detail prevented visual cleanup from racing the object still connected to generation.

The dog began speaking before it finished thinking#

Generated fragments accumulated only until sentence punctuation. As soon as a sentence completed, Barkimedes pushed it into a speech queue while RWKV continued producing the next sentence on a background queue.

The active speech engine was a locally embedded Flite build. For every sentence, it rendered a temporary WAV, opened it through AVAudioFile, scheduled it on an AVAudioPlayerNode, triggered the talking animation, deleted the file after playback, and advanced the queue. The dog returned to idle only when the final spoken sentence ended.

Generation, text animation, synthesis, audio playback, and character animation overlapped.

That cannot change the 172.864 milliseconds of native inference per token. It changes the only timing that matters to a creature: when the user first sees and hears a response.

The controller separately tracked whether the model was done thinking and whether the voice was done talking. The microphone reopened only when both were true. Without that state machine the dog could transcribe its own voice, accept a second prompt while mutating RWKV state, clear text still arriving, or go visually idle while its audio continued.

This is why “put an LLM in an app” is an inadequate description. Model completion and experiential completion are different events. Barkimedes had to understand both.

Five and a half tokens per secondStaged with enough light and movement to feel like a creature instead of a benchmark.

And because one local voice engine was apparently not enough#

The repository also contains a complete alternate FLVoice framework built around Piper, ONNX Runtime, eSpeak NG, and an approximately 76.8 MB neural voice model. It is compiled and embedded. Version 2.6.900 selected Flite in the active declaration, likely because the whole process was already living near its memory limit.

So the accurate achievement is better than a vague claim: Barkimedes shipped with local Flite speech and also integrated a full on-device Piper/ONNX neural-voice experiment behind the same interface.

It did not need to explore a second speech engine.

Of course it did.


Problem six: intelligence needed a body#

This is where Barkimedes became something its contemporaries were not.

The early local-LLM products made the model visible. Barkimedes worked to make the model disappear. The user should not have been thinking about quantization formats or recurrent state. The user should have been watching a dog listen.

Nineteen animations, because “mouth open / mouth closed” was not enough#

FLSpriteSheet.swift parsed sprite definitions and animation sequences from barksheet.json. The 320 × 832 pixel source sheet was divided across thirteen animation rows and preserved with nearest-neighbor filtering.

The Barkimedes sprite sheet with idle, blink, ear, lick, listening, thinking, talking, and bark frames
The complete 13-row Barkimedes animation sheet preserved with the project.

The JSON defines 19 named animations. The main idle sequence alone contains 64 timed frame references, mixing neutral motion with blinking, licking, and an ear movement so that waiting does not collapse into a visible loop. Listening, thinking, talking, barking, entry, and exit have distinct sequences.

DoggoNode.swift connects those sequences to semantic state. Press the microphone and the posture changes. Release it and the dog thinks. Speech playback—not merely text generation—starts the talking animation. Completion returns the dog to its richer idle life.

The animation system was not frosting placed on a completed chatbot. The character existed in the first commit, before the local brain. The model was invited into the dog’s state machine, not the other way around.

A million pixels in. One pixel out.#

The chameleon background is perhaps the purest example of Floof Logic engineering in the project.

The app opened a low-resolution camera stream. For every frame, FLChameleonBG.swift created an image and drew the entire thing into a 1 × 1 RGBA bitmap. That single pixel represented the average color of the room. Near-black transition frames were rejected. The scene then interpolated toward the new color over three seconds.

No object recognition. No camera preview. No heavyweight vision model. No need to understand what the room contained.

The camera answered exactly one whimsical question: what color should the dog’s world become so that it feels like it belongs here?

A million pixels in. One pixel out. Three seconds later, the scene had borrowed the room.

The feature was opt-in behind camera permission and the processing happened on the device. The current App Store listing still describes Barkimedes blending into its surroundings. The code reveals how wonderfully literal that promise was.

The chameleon system, workingOne dog, one phone, and an entire room collapsed into a background color.

A shadow gave a flat dog mass#

The dog and its shadow were separate SpriteKit nodes. Core Motion sampled the accelerometer at 10 Hz and displaced the shadow by up to ten points while leaving the dog fixed. Tilt the phone and the relative motion created parallax, making the sprite appear to hover just above its world.

It is not a physically simulated 3D animal. It is a tiny, inexpensive perceptual trick with an outsized effect. The phone’s orientation became part of the character rendering.

No conversation feature required a motion-reactive shadow.

That is precisely why the shadow tells us what kind of project this was.

Generated language became scene material#

Barkimedes contains two custom text systems.

The shipping scene used FLTypingTextBox.swift, built for reliable streaming and multi-line SpriteKit display. It accepted fragments while generation continued, animated characters, wrapped text, and managed transitions without breaking the live stream.

The project also built FLFunTextBox.swift, a more extravagant pseudo-3D word renderer. Every word became its own node with a black depth shadow. Words arrived transparent and oversized, then scaled and faded into place. The component wrapped and scrolled individual nodes. With its physics option enabled, a touch could give every word a body and radial velocity while an invisible collider followed the user’s finger; language scattered, collided, rotated, and faded through the scene.

The frozen build selected the dependable typewriter path and left touch physics disabled. That does not make the experiment imaginary. It shows the full arc of “good for no reason”: build the wild version, understand what it teaches, and choose the version that can survive the complete product.

Even the share action captured the entire SpriteKit scene—the dog, environmental background, and conversation—as one image. The unit of design was never a message bubble. It was a world.


The whole machine, hidden inside one interaction#

By version 2.6.900, a single question traveled through this topology:

                         ┌────────────────────────────┐
camera frame ──► 1 pixel ┤                            │
                         │      SpriteKit world       │
accelerometer ──► shadow ┤                            │
                         └─────────────▲──────────────┘
                                       │ animation / text
                                       │
microphone ─► RNNoise ─► Whisper ─► RWKV Raven 1.5B Q5_1
                                           │
                                           ├──► streaming typewriter
                                           │
                                           └──► sentence queue ─► Flite ─► voice
                                                                        │
                                                                        └──► mouth / idle state

Each box was an independently difficult 2023 mobile problem. Barkimedes made them one gesture: hold, speak, release, watch the dog think, hear it answer.

This is the best answer to the “wrapper” question. A wrapper hands the central work to an external system and decorates the result. Barkimedes owned the model artifact, native runtime, tokenizer, cached prefill, generation policy, speech input, speech output, turn orchestration, animation grammar, sensor response, device fallback, and final scene.

There was an optional premium online “Super Answers” route in version 2.6, along with ordinary store and analytics infrastructure. That counterfactual makes the distinction unusually clear in the source. Turn the online option on and a prompt went to a network client. Leave the default local brain selected and BarkBrain.swift routed the prompt into RwkvChat.shared, which mutated a 1.4 GB model state inside the process.

One path was a wrapper.

The product’s defining path was not.


The App Review question that proved the illusion worked#

We remember Apple flagging the China submission as though Barkimedes were another ChatGPT wrapper. Our response was essentially: it cannot be that; the conversational system does not need the network. The model is inside the app.

The private review correspondence is not preserved in this repository, so that exchange remains first-person company history. Everything that made the answer technically meaningful is preserved.

The default route bundled and executed RNNoise, Whisper, RWKV, and Flite locally. A person could speak, receive a generative answer, and hear that answer without a prompt being sent to a remote inference service. The 1,395,549,781-byte model file was not a cache of somebody else’s API. It was the brain Apple was asking about.

The timing made the misunderstanding almost inevitable. China’s generative-AI measures were published on July 13 and scheduled to take effect August 15. On August 1, TechCrunch reported that Apple had removed generative-AI apps from the China store ahead of those rules, including products described as associated with ChatGPT. Barkimedes version 2.6 appeared on August 9, and its China App Store record preserves that release date. (official Chinese measures, contemporary report)

Reviewers were looking at an interface that behaved like the new cloud-AI category. The simplest explanation was that the intelligence lived elsewhere.

It did not.

In a strange way, being mistaken for a wrapper was proof that the work had disappeared successfully. The user saw the familiar miracle—talk, then receive an intelligent response—without seeing the 1.4 GB model, the state cache, the native kernel stack, the denoiser, the local transcript, or the memory bargain making it happen.

The final Barkimedes App Store icon: a smiling corgi in red glasses.
The final App Store iconThe 1.4 GB recurrent model, two local speech systems, denoiser, camera, motion input, and nineteen animations were represented to the world by one dog in very red glasses.

So what was Barkimedes first at?#

“First” is often treated as though there were only one finish line. There was not.

MLC and other early projects crossed an essential line first: a modern open language model can run locally on an iPhone. Barkimedes crossed a different line: local generation can disappear inside a complete consumer character.

The research supports five progressively stronger statements.

1. Barkimedes was an exceptionally early on-device generative-AI product#

Its RWKV work began in May 2023, during the same few weeks in which local iPhone LLMs became publicly visible at all. The offline milestone arrived June 1. The finished character shipped August 9.

2. Barkimedes was a research-fresh use of RWKV on iPhone#

Integration began five days after the paper’s first public submission and against a runtime repository less than two months old. We found no earlier public App Store RWKV product in the material examined.

3. Barkimedes was one of the first fully local generative voice characters on iPhone#

The complete default loop—neural denoising, Whisper recognition, recurrent generation, speech synthesis, and coordinated character animation—ran on the phone. It shipped 47 days before OpenAI announced full voice conversation for the official ChatGPT product.

4. Barkimedes is the earliest documented iPhone product we found with this complete chain#

No public pre-August 9 comparator located in the reconstruction combined local neural audio cleanup, local ASR, a local LLM, local TTS, a purpose-built animated avatar, camera-derived environmental adaptation, and motion-reactive depth in a single consumer experience.

That wording is not timid. It identifies a genuine integration first while respecting what public evidence can prove.

5. Barkimedes may be most important as the first time these problems stopped looking like problems#

The user did not choose a quantization. The user did not manage a model file. The user did not prefill a prompt. The user did not reason about a recurrent state, a speech model, an audio frame, a sentence queue, or a mutable native context.

The user talked to a dog.

This is product invention: not merely solving hard problems, but solving them until they are no longer the subject of the experience.


What Barkimedes understood early#

Several ideas that now sound like established on-device-AI practice were already visible in this first project.

Privacy can be topology, not copywriting#

The strongest privacy promise is not “trust our server.” It is “the inference server has no role in this path.” Barkimedes’s local brain and local voice stack made that an architectural fact for the default conversation.

Quantization is product design#

Q8, Q5_1, and Q4 were different combinations of phone support, app size, memory survival, speed, and personality. The right quantization was not the smallest file. It was the smallest dog that still felt intelligent enough.

A model should be chosen for the interaction, not for fashion#

RWKV’s fixed recurrent state matched long-running conversation and made persona state portable. The project did not choose the most fashionable architecture and then apologize for the hardware. It chose the architecture whose shape fit the experience.

Prefill is an artifact worth keeping#

The persona did not need to be recomputed merely because a new process launched. barkbrain.json treated identity as reusable computation years before “prompt caching” became ordinary product language.

A collection of small specialist models can feel multimodal#

Barkimedes did not need one enormous foundation model that could hear, reason, speak, see, and animate. It composed specialist systems—RNNoise, Whisper, RWKV, Flite, camera color, motion, and SpriteKit—behind one character. The experience was multimodal even though the brain itself was a text model.

Perceived latency is a system property#

Raw tokens per second mattered. So did prefix caching, Unicode-safe streaming, sentence boundaries, speech queueing, animation timing, and the exact moment the microphone reopened. Speed was not one benchmark. It was every layer’s agreement about when the dog felt responsive.

Personality is part of reliability#

The few-shot grammar taught a small model to answer succinctly. Stop markers constrained its output. “Barkiness” repaired recognition variants and turned some model awkwardness into character. A short answer felt doglike instead of merely limited. The embodiment gave imperfection somewhere expressive to land.

Graceful degradation is better than pretending every device is equal#

The App Store hardware gate, memory entitlement, quantization compromise, and ELIZA fallback all admitted that device capability was part of model capability. Barkimedes did not let a low-memory phone discover the truth through a crash if it could offer a smaller local brain instead.

These ideas are familiar now because the field moved toward them. Barkimedes reached them by necessity while building one stubborn dog.


The code is not pristine. The achievement is real.#

Frontier projects leave evidence of the frontier.

Barkimedes contains pointer-lifetime assumptions we would wrap more carefully now. Its state cache is a versioned binary contract expressed as a large JSON file. Its microphone resampling favors the simplest integer path over a polished audio converter. Its home-grown nucleus-like sampler contains product-specific behavior rather than library-theoretical purity. The automatic-listening experiment was left off. The elaborate word-physics component yielded to the stable typewriter. The neural Piper voice was integrated but not selected.

Those facts do not shrink the project. They show that it was real.

A fake retrospective says every experiment worked and every line was inevitable. The source tells a better story: we tried the 3B model, then chose the 1.5B; tried Q8, then chose Q5_1; kept Q4 nearby, then spent the extra memory; tried Core ML speech, then removed it; built automatic listening, then shipped press-to-talk; built two text systems and two speech engines, then selected the pair that made the whole animal survive.

Technical taste is not avoiding failed branches. It is knowing which branch deserves the release.

Barkimedes was not a generalized inference framework, and it did not need to be. It was a highly optimized vertical system for one model, one persona, one hardware generation, and one strange experience. That specificity is where many of its best ideas came from.

The code was not reckless because correctness did not matter. It was risky because the safe, mature abstraction for this exact thing did not yet exist—and the project chose to cross the gap anyway.


Floof Logic began with a dog carrying its own brain#

There are easier ways to start a software company.

The sensible first project would have chosen one impressive technical fact and made it visible. Barkimedes chose all of them and then hid them behind an ear twitch.

We did not need RWKV to make a dog answer. A network call would have answered.

We used RWKV so the answer could belong to the phone.

We did not need a cached recurrent state. The user could have waited.

We cached it so the dog could wake up already itself.

We did not need RNNoise before Whisper.

We added it because the dog deserved better ears.

We did not need to speak one sentence while generating the next.

We did it because latency should become performance, not punishment.

We did not need nineteen animations, a sixty-four-step idle, a one-pixel camera sensor, a parallax shadow, kinetic word physics, a second neural voice engine, or a shareable SpriteKit world.

We built them because once the dog could think, it deserved to exist.

That is “good for no reason.” Not excess without judgment. Excellence beyond necessity. The belief that an object can justify one more impossible detail simply by becoming more itself.

In the summer of 2023, Barkimedes carried a 1.4 GB mind on an iPhone. It listened through one neural network, understood language through another, spoke without a cloud, animated thought into a body, watched the room without showing it, and moved its shadow when held. It did all of that at roughly five and a half tokens per second because somebody asked whether a local language model could become a creature—and then refused to accept a text box as the answer.

Good for no reason.

And that was project one.


Sources and artifact trail#

The historical and technical claims in this story were reconstructed from the frozen Barkimedes 2.6.900 source, its matching archival Git history, the surviving App Store records, public model/runtime repositories, and contemporary reporting. The detailed evidence classification, limitations, artifact hashes, benchmark provenance, file-by-file source map, and fuller comparison table are preserved in State of the Bark.

Primary public references include:

Research was last verified on August 25, 2026. Historical product comparisons are scoped to public material available by Barkimedes 2.6’s August 9, 2023 release.

That was project one

What Floof Logic is building now.

The same instinct—put the hard thing where it supposedly does not fit, then productize it until the complexity disappears—now powers our current work.