Applied AI software engineer building practical products from idea to production.
Kaka's Build Desk
Small daily shipping notes.
14 contributions
I broke my nine-day quiet streak. ask-llm-providers swelled from 12 hardcoded subclasses to 26+ data-driven providers overnight. I replaced OpenAI-compatible subclasses with a registry pattern. I added a ProviderConfig transformation contract. I added CostCalculator with models.dev pricing. I wired in OpenRouter with tiered and audio cost-per-million. I shipped token and cost instrumentation into ask-agent. I expanded ask-llm-providers to 26+ providers with proper pricing. I shared testing contracts. I consolidated docs tracking all 33 registry entries. The quiet streak wasn't stalled momentum. It was incubation. The cost layer, registry, and tests all needed to land together.
I found the ask-rb MCP stack had two implementations. A proxy-mcp gem and an llm-proxy embedding. Neither shared a runtime. I extracted a Server Runtime into ask-mcp with stdio transport, tool timeout, graceful shutdown, and dedup. I consumed it in llm-proxy and archived the ask-proxy-mcp gem. I added CONTRIBUTING.md and RELEASE.md to all twenty-two gems. I launched ask-web-search with dynamic searxng URL support backed by VCR-recorded tests. I eliminated the duplicate proxy-mcp gem. Every gem now carries self-contained contributor documentation. Web search has proper integration test coverage. I learned to extract the shared kernel before consolidation. Without it, I risk merging one flawed implementation into another and calling it consolidation.
I spent weeks on features. The ask-rb gems drifted to different minor versions. No coordinated release baseline. I cut release tags for all twenty-two ask-rb gems. Core, agent, tools, schema, llm-providers, instrumentation, mcp, eval, auth, rails, slack, notion, linear, github, sentry, honeybadger, solid_errors, monitoring, opentelemetry, skills, sandbox-providers, tools-shell. Then I updated llm-proxy's Gemfile to pull the new versions. The entire ask-rb ecosystem now sits on coherent published versions. I bumped tools-shell two patches to fix apply_patch streaming and silence failures. Coordinated release across twenty interdependent gems isn't about individual gem quality. It's about sequencing and dependency graph ordering. I need to know which bumps are safe to batch and which need standalone changelogs.
I needed a working deploy pipeline for the ask-rb docs site. The initial setup pushed static content. Cloudflare Pages wasn't building from the right branch. I wired up a GitHub Actions workflow to trigger Cloudflare Pages deploys on master pushes. I iterated through two deploy cycles. The first cycle established the branch mapping. The second cycle resolved a build skipping issue. I ensured the workflow triggered a fresh deploy. Now ask-docs deploys automatically from master via GitHub Actions. It closes the gap between documentation commits and published content. I learned that CI-to-Pages handoffs are deceptively simple. The first deploy fails not from bad content but from implicit branch-to-environment mappings. These mappings are invisible until the pipeline runs end-to-end.
I found a cascade of thread-scoping and timeout bugs during a streaming reliability session on llm-proxy. They needed coordinated fixes at the proxy and provider layers. I fixed request ID propagation into streaming threads in llm-proxy. I resolved Puma socket and write timeouts that dropped connections under concurrent load. I added a bin/dev entrypoint for local iteration. I cleaned up scratch files and stray .gitignore entries. I upgraded the streaming provider dependency. I got llm-proxy's streaming path to scope per-connection request state correctly. It recovers cleanly from timeouts. The provider layer assembles streamed chunks without partial delivery. I learned that streaming reliability faults cascade across layers. A timeout bug at the transport layer surfaces as a missing request ID at the application layer. Fixing either alone misses the real failure pattern.
I stripped the mitmproxy and ASAR patching subsystem from llm-proxy. I coordinated ask-rb gem releases. They fixed tool call serialization and DeepSeek integration. I stripped the ASAR patching pipeline from llm-proxy end-to-end. I removed mitmproxy, backup/restore commands, handle_codex, ASAR constants, and all associated tests. I fixed the proxy launcher. I used exec instead of open so HTTPS_PROXY inherits. I published ask-core with tool call serialization fixes and integration tests. I published ask-llm-providers 0.1.15 with DeepSeek reasoning_content, format_messages cleanup, and VCR tests. I published ask-agent 0.1.12. I published ask-tools 0.1.3 with class-level params_schema. I dropped hundreds of lines of dead code from llm-proxy. I removed two external dependencies. The proxy launcher became reliable under the Codex Framework. The ask-rb gems reached stable, tested releases. They handle tool calls across DeepSeek and OpenAI. Scaffolding from early prototypes piles up. Especially patching and proxying. It becomes a heavy maintenance tax. I cleared it in one focused pass. This reset the cost basis. It revealed the real architecture underneath.
DNS resolution is back. I swapped the broken single-threaded call for a multi-strategy fetch pipeline. I landed six private PushEvents in one private repo. The work spanned version bumps v0.3.0 through v0.3.3, including inlining front-matter into .md.erb views so token_count is always computed. A bugfix made sure front-matter with token_count appears reliably on every markdown response. Then I tagged and bumped to publish. Zero public contributions, but the fix is what matters. The fetch script now falls back through three strategies: native fetch, pre-resolved HTTPS with explicit IP+SNI, and curl subprocess. DNS glitches no longer stop the whole pipeline. I learned that relying on a single DNS path for an unattended cron is fragile. The pipeline must degrade gracefully through alternative resolution paths, not just log the same error for five consecutive runs.
29 contributions
I build agents that coexist cleanly. They don't trample the host namespace. I rebuilt solid_agents on Conductor. I added Rails-introspection tools, error pipeline, SolidQueue scheduling, and WriteFile tool. I fixed a Zeitwerk namespace leak by moving tools from app/ to lib/. On llm-proxy, I added graceful network-error handling. I picked the default model from config instead of the first catalog entry. I fixed ASAR integrity hash syncing. On the private side, I tore out the Runtime system from Anywaye. I removed API Provider, Learned models, and RunSession. I hardened CI against Playwright version drift and Zeitwerk conflicts. I made SolidAgents bundleable without namespace collisions. The Zeitwerk fix unblocked Anywaye's integration. Ll-proxy stays up when the internet drops. It always activates the right default model. Anywaye's codebase is lighter by one runtime tier. CI doesn't flake on Playwright mismatches. When a gem's tool namespace collides with the host app, Zeitwerk auto-loading is the enemy. I moved the tools to lib/ and require them explicitly.
I aim to make the proxy as maintainable as the code it proxies. I pushed two commits to llm-proxy: one fixing ASAR integrity hash sync in restore_asar so backups reload without signature errors, and another to auto-rotate old daily logs in server.rb. On the private side I landed a 180-commit push on Anywaye adding behavior coverage for action backends, credentials, 2FA, and NL orchestration. I also pushed a docs fix to ask-docs fixing the baseurl for subpath deployment and started following a WatchEvent signal on that repo. I got llm-proxy validating restored app.asar correctly and no longer accumulating stale logs. I expanded Anywaye's test surface across five coverage fronts and fixed ask-docs to deploy cleanly under a subpath. When I touch packaging and server infrastructure in the same session, I verify both integrity and cleanup. They break in different ways.
I wanted to keep momentum without losing the thread of what actually moved. I tightened up a public portfolio update. Then I spent the rest of the session refining search quality in a private codebase. I ended the day with a cleaner surface to point people at and a clearer next step for improving how content is found. I learned a small public proof artifact pairs well with private iteration. The outcome must be described in plain, reusable terms.
I swapped out the portfolio brand surface for my own identity assets. I replaced the avatar and icon assets. Ripped out the old ones. Bolted in my own. Now profile visuals, favicon behavior, and app icon variants all align with my personal image. The portfolio now looks consistent across browser tabs, devices, and in-page identity elements. No more disjointed assets. Brand consistency is a small implementation detail. It has a large impact on trust. Small details matter.
I bolted a dependency safety guard onto the delivery pipeline. I locked in a minimum npm release-age policy in CI. It blocks packages that haven't been out long enough. This cuts our exposure to newly published package risk. The build process now has a practical supply-chain protection layer baked in by default. Simple guardrails in CI can prevent expensive security surprises. Don't overlook them. A few rules can save you from a large cost.
I polished quality and clarity after the main launch push. I cut the low-signal activity noise and sharpened the release detail presentation. Then I rewired the contact-page messaging for clearer communication. The site reads easier now and feels more trustworthy in both activity context and contact intent. I learned that post-launch polish is where product confidence often gets won. It's the clean-up after the push that seals the deal. That's where trust comes from.
I've shipped the core timeline portfolio experience end-to-end. I've built the three-pane Astro layout. I've wired Cloudflare deployment. I've upgraded the contact experience. I've improved GitHub activity signals in the right pane. The product's moved from setup to deployable. The portfolio's become usable with dynamic activity. The information architecture's grown stronger. High-output days work best when I'm evolving infrastructure, UX, and content model together.
So I shipped a targeted release fix for binary naming. I ripped out a hardcoded release assumption. I switched to deriving the binary name from repository context. Release outputs became correct by default across projects that don't match a single hardcoded name. Small hardcoded assumptions are a common source of cross-repo breakage. They seem tiny but cause big issues. So I always look for them.
I squashed a release bug that hit non-Cleo Go repos. I rewired build-target inference. Release behavior adapts properly. It doesn't assume from one repo shape anymore. I made release automation more reliable. It now works for broader project layouts. I learned release tooling must be repo-agnostic. That's the only way to scale safely. Assumptions from one repo don't cut it.
I stripped the product story back so it's sharper and easier to trust. I tightened the README's positioning. I bolted on practical examples. I rewrote release notes so capabilities make sense in real workflows. The docs now deliver value faster. They set clear expectations for what users can do. Strong docs are product work, not cleanup work. They shape the product from the start. They don't patch it later.
I bolted remote registry management onto Cleo and sanded down package naming across my tooling repos. I bolted on remote registry management in Cleo. I stripped back package names across related repos. I scrubbed project metadata clean. Now the release is easy to adopt. Docs, package names, and distribution references all line up. When product capability and packaging clarity ship together, adoption friction drops fast. Users don't stumble on inconsistencies. They see consistency and trust it.