Pinned Tweet
Every time I hit a wall with one model, I used to paste my whole thread into another one and explain the project from scratch. That part wasted more time than the actual work.
llmwise.ai puts 16 models from 7 companies in one chat, on one plan. Switch models mid-chat and the next model sees the whole conversation. No re-explaining your project.
I pick a model per message, and the message count shows before I send. My usual move: start on a fast model for the boring first pass, then switch to a stronger one for the hard part, same thread.
Pro is $20 a month plus tax. The monthly allowance is mixable, up to 125 messages on Claude Sonnet 5-class models, plus 60 fast messages a day.
Helps anyone juggling more than one AI subscription.
Interesting repo: Pinvou/pinvou-agent (2650 stars).
It is an open-source desktop AI agent workspace. It is written in Rust. It puts everyday work, visual design, and coding in one app. The goal is a result, not another chat reply.
What you can do with it:
Attach PDF, Office documents, images, and text files. Drag, drop, or paste them in.
Build a local knowledge base with full-text and vector retrieval. Attach several collections to one chat and switch each one on or off.
Run Codex, Claude Code, or Kimi through ACP in the same desktop window. The coding agent reads and edits a real project. It runs commands. It shows plans, tool steps, permission requests, and file changes.
One concrete detail from the readme: the artifact panel collects every file the agent creates or edits. You preview, locate, and open them in one place. Markdown artifacts are editable. You can select a passage and ask the agent to revise it.
Second detail: Plan and YOLO modes. Plan mode shows the plan first for complex work. YOLO mode executes directly when the task is clear.
Third detail: sessions stay bound to their workspace. You can continue a session after you restart the app.
Privacy: run a local model for a fully private loop, or connect any OpenAI-compatible endpoint.
Extend it with MCP servers, CLI connectors, Skills, and workflows. A memory center captures long-term preferences. You review and confirm each candidate before it is saved. A persona card pool lets you save specialist roles for different domains.
There is also a 90-second feature demo in the readme (Chinese).
Bookmark it if you want a desktop agent that ends with a file, not a paragraph of text.
Most PDF tools upload your file to a server. PaperPilot does not.
PaperPilot is a PDF toolkit written in Rust. One engine runs on five surfaces. These are an MCP server, a CLI, a browser build, a desktop app, and a local REST API. The browser build uses WASM. The desktop app uses Tauri and Svelte. No Chromium. No C++ runtime. No cloud calls. It is at v0.6, and the community edition is Apache 2.0.
What it means for builders:
1. Your coding agent gets PDF tools. PaperPilot ships a local stdio MCP server. Codex, Claude Code, Kimi Code, Pi, Claude Desktop and Cursor connect to it. Add the binary to claude_desktop_config.json, restart, then ask it to merge two PDFs and compress the result.
2. The CLI covers batch work. Merge with paperpilot merge --inputs doc1.pdf doc2.pdf --output merged.pdf. Compress with --quality 75. Rotate pages 1 and 3 to 5 with --angle 90.
3. The REST API is one command. Run paperpilot serve --port 7823. Then POST to /api/v1/pdf/merge from Python, Node or n8n. Swagger docs sit at localhost:7823/docs.
4. The browser build never uploads. Open usepaperpilot.com and watch the Network tab. You will see no file uploads. Files stay in browser memory.
5. v0.6 does real work. Organize: merge, split, rotate, delete, reorder, extract, booklet imposition, N-up grid. Optimize: compress. Extract: plain text and OCR through pure-Rust PaddleOCR via rten. Security: watermark, validate signatures, remove signatures, PII scan, deep sanitize. Office data: Excel to JSON and Excel to CSV.
The honest limit: the export formats are not here yet. PDF to Markdown, HTML and JSON land in v0.7. PDF to Word, Excel and PowerPoint land in v0.8. Encrypt, decrypt, redact, forms and annotations are v0.9.
Build it yourself if you want. You need Rust 1.75 or newer, Node.js, and pnpm. Then run cargo build --release with the cli, mcp and gateway packages.
Which PDF step do you still do by hand in your agent pipeline?
Unit tests for the happy path take five minutes. The edge cases take the afternoon. These prompts do that part.
1. "Here is one function. List every input it can receive: empty, null, zero, negative, maximum, and wrong type. Do not write tests yet."
2. "For each input in that list, name the branch it hits and the line number. Mark any input that hits no branch."
3. "Write one test per boundary: empty string, one character, the maximum length, and one character past it. Use the test framework already in this file."
4. "Write the failure tests first. Assert the exact error type and the exact message. Do not assert only that it throws."
5. "Add a test that calls the function twice with the same input. Assert both results are equal. Name the state that could break this."
6. "Pass a wrong type on purpose. Show what the function does today, not what it should do. Mark the gap in a comment."
7. "List every dependency this function calls. Write one test that fakes each dependency, and one test where each dependency fails."
8. "Here is one line from the function: <paste line>. Show the test that fails if someone deletes it. If no test fails, tell me the suite has a gap."
9. "Name each test so the failure message says what broke. Use this format: functionName_condition_expectedResult."
10. "Give me the smallest set of tests that hits every branch. Delete any test that does not change the result. Show the count before and after."
The last one is the one I run most. Most generated suites are too long and too shallow.
Save this before your next refactor. Reply with the prompt you would add, and I will test it on a real function.
A 200 status code only tells you the request arrived. It says nothing about the data inside.
I built a tool that fetched records. The API answered 200 every time. Some calls came back with an empty list. My agent did not notice. It wrote a report about nothing and passed it downstream.
An empty result is not an error to the HTTP layer. It is an error to your tool. So check the payload, not the status.
Here is the checklist I run now.
1. Read the status code. Then ignore it and check the shape.
2. Validate the schema, not just the field names. A field can exist and be null.
3. Count the rows. If the tool promises a list, assert the list is not empty.
4. Check required fields on every item. One missing id breaks the next step.
5. Compare against a baseline. If the last good run returned records and this one returns zero, stop.
6. Log the raw payload on failure. Truncate the values, keep the keys.
7. Fail loud. Raise a typed error. Do not return an empty list.
The last point matters most. An empty list moves downstream and looks like valid data. A raised error stops the chain.
Concrete detail: put the check in one place, a wrapper around every tool call. Validate with a schema library first, then add a minimum item count. Something like `if not items: raise ToolOutputError(name, raw)`. Keep the raw payload inside the error object. You will want it when you debug later.
Two things to avoid. Do not trust `response.ok` and move on. Do not retry on empty data. Retry on errors. Empty data needs a different query, or a human look.
How do you validate tool output in your agents? Schema only, or counts and baselines too? Share your approach.
You can run many Claude Code and Codex agents at once. The hard part is knowing which one waits on you.
Harp puts every agent session in one sidebar. Each row shows the state.
What it is: Harp is an unofficial fork of the open source Warp terminal. It replaces the tab bar with a sidebar built for long running coding agents. The rest of Warp stays as it is.
A row shows one of three states: working, waiting for you, or done. An unread mark stays until you look. A dot means background work still runs. Cmd+R renames a tab.
What it means for builders:
1. Groups survive a restart. Put tabs into named groups. With the tmux integration on, the group and the order are stored on the tmux sessions. Other tmux clients see the same layout.
2. Limit rings sit in the footer. Two rings per provider: the 5 hour window and the weekly limit. Hover one for the numbers and the reset times. Codex values come from its logs in ~/.codex/sessions. Claude values come from Claude Code's status line. Harp fetches nothing and reads no credentials.
3. It runs next to Warp. Harp has its own bundle id, its own URL scheme and its own settings folder at ~/.harp. Nothing is shared. Settings live in ~/.harp/settings.toml and the app reloads the file when it changes.
4. Updates come from GitHub releases. Harp checks the latest release every 10 minutes. It downloads the DMG in the background, checks the signature against Harp's Developer ID team, then offers a restart.
5. The extras are off by default. Turn tmux sync on in settings.toml. It reads names, groups, order and flags, and polls every 10 seconds. The limit rings are the exception and start on.
One honest limit. Logging in through Harp is untested. The Claude rings also need a Claude.ai plan, not an API key. They appear after Claude Code's next answer.
Which signal do you check first when several agents run at once?
Source: github.com/dominikmartn/harp
A single timeout on the whole run is the wrong control. It kills your good long task and lets the stuck step sit there.
Most agents have one timeout for the whole run. Two failures come from that. The run dies at the limit while a long but healthy task is almost done. And a stuck tool call holds the run open until the same limit.
The fix is two timeouts.
Per step timeout. One limit for each unit of work: a model call, an HTTP fetch, a shell command, a database query. Each step gets its own budget. A file read and a browser fetch do not need the same number.
Run deadline. One limit for the whole job. Keep it as a final guard, not as the main control. Set it from the sum of your step budgets plus slack. Do not pick a round number once and forget it.
Checklist:
- Put a timeout on every outbound call, not only the top level.
- Cancel the work on timeout. Do not only stop waiting. A shell command keeps running after you stop reading it.
- Log the step name, the elapsed time, and the input on every timeout. A slow step and a stuck step look the same without this.
- Make retries safe. A retried step must not write twice.
- Add a heartbeat for long steps. A step that reports progress is alive, even after a long time.
- Checkpoint before a write. A run deadline that fires mid write leaves partial state.
Avoid one shared constant for all steps. That constant is too short for the slow step or too long for the stuck one.
In my step config I keep two fields: timeout_ms for the step and deadline_ms for the run. The run deadline is derived, not typed by hand.
Do you set the timeout per step or per run? Tell me which step in your agent always needs the longer budget.
the reward function is still the hard part, the rest is just compute.
Meta’s Muse Spark Open is live on the Baseten Loops SDK for post-training.
Train it on your data with your reward functions; Loops runs the training and sampling infrastructure.
When your checkpoint is ready, deploy it straight to a production inference endpoint.
docs.baseten.co/loops/quicks…
Quick connect post: I build AI agents for small teams.
The one handoff I trust is planner to checker. The checker gets the written plan only, not the chat history. The plan must stand alone, so weak steps show up fast.
I have 10+ years as a senior SRE with Kubernetes, AWS and Terraform. I also write arXiv papers on chain-of-thought faithfulness. That work makes me trust written steps over hidden reasoning.
Reply with what you're building. I follow back builders.
an agent passes in staging and fails in production. the gap is usually env drift: different vars, different keys, different model version, different network rules.
what is your first check when that happens? not the full list, just the one thing you run before anything else.
one prompt change can shift output quality. no code diff shows it.
a single prompt edit is hard to roll back without a naming scheme.
how do you name and version your prompts so you can roll back one change? file per version, git, a registry, or something else?
Nvidia 3000 cards ship with a lower FP/BF16 issue rate than the same chips get in professional cards. A small kernel module now sets the higher rate before the driver loads.
What it is: a Linux kernel module for GA102, GA103, GA104 and GA106. It runs before the NVIDIA driver binds the card. It writes two speed selectors and does a FLR. SS0 is 0x88888888, which selects the full BF16 rate. SS1 is the 4-bit 0x8 for IMLA4. It is not a UEFI application. It is not a patched driver. You do not patch again each time Nvidia ships a new driver.
On one RTX 3090 Ti at 450 W, dense 8192³ GEMM, five-sample medians, FP32 accumulation:
FP16: 87.46 to 118.39 TFLOPS
BF16: 87.50 to 157.41 TFLOPS
TF32: 42.58 to 82.61 TFLOPS
What it means for builders:
1. The module doubles the FP/BF16 FMA issue rate into FP32. That is the mechanism. Everything else follows from it.
2. Reported gains vary by card. RTX 3090: +25 to 67%. RTX 3080 10 GB: +70 to 73%. RTX 3070: +73 to 81%. RTX 3060 12 GB: about +80%.
3. Power limit decides the result. The lowest figure, +25%, came from cards capped at 225 W. Check your cap first.
4. Matrix-heavy work speeds up. LLM prefill gained 14 to 36% in several reports. Diffusion and FlashAttention also improved.
5. Memory-bound work does not move. LLM decode and INT8 stay about the same. Reports that compared outputs found them bit-identical.
Install takes two steps. Clone the repo, then run make install. Then add the module's targets=all option to your kernel command line. The build checks SHA-256 on the pinned Nvidia inputs.
The honest limit: the RTX 3080 Ti 20 GB OEM completes the module but keeps BF16 at half rate. That card is GA102. GA103 has no reports yet. Each gain comes from the reporter's own benchmark, so the numbers are not directly comparable.
Which of your workloads is issue-bound rather than bandwidth-bound?
Most staging bugs are prod bugs you never let staging see. The values files are the reason.
Your staging values and your prod values drift apart. One file gets a new key. The other does not. Staging passes. Prod breaks at 2am.
Some values must differ. Replicas. Hostnames. Resource sizes. Credentials. That is fine.
The rest must be identical. Here is the list I check.
1. The key set. Same keys, same nesting. A prod-only key is a code path staging never runs.
2. Chart version and appVersion. Pin both. A floating chart version runs different templates in each environment.
3. Probe paths and ports. Timing can differ. The path and port cannot.
4. Label and selector keys. A mismatch breaks Service selectors with no error.
5. Container port names. Named ports fail silently when the name changes.
6. securityContext. If staging runs as root and prod does not, staging proves nothing.
7. Env var names and config key names. Values change. Names do not.
8. Secret key names. The values differ. The keys must match.
9. The limit to request ratio. Absolute numbers change. The ratio should not.
10. Subchart versions. Same chart, same dependency versions.
What to avoid: one values.yaml with if/else on environment. It hides the diff. Keep a shared base file plus one file per environment.
Concrete check, run in CI:
yq -r 'paths(scalars) | join(".")' values-staging.yaml | sort > s.txt
yq -r 'paths(scalars) | join(".")' values-prod.yaml | sort > p.txt
diff s.txt p.txt
Fail the build on any line. Add values.schema.json with required keys. A missing key then fails at render time, not at runtime.
What is the one value you refuse to let differ between environments? I want to see if it matches mine.
Most Argo CD rollout failures I debug are not bad images. They are bad order.
A sync applies many manifests at once. A database migration runs beside the API that needs the new column. The pod crashes. You roll back. Nothing was wrong with the code.
Sync waves fix this. You add one annotation. Argo CD applies the lowest wave first. It waits for those resources to be healthy. Then it moves to the next wave.
The order I use after a few painful weeks:
Wave -1: CRDs, namespaces, resource quotas. Nothing else.
Wave 0: config maps, secrets, services, deployments. This is the default. Leave most things here.
Wave 1: the app that depends on the database.
Wave 5: smoke test Jobs and hooks. They run last and they must pass.
Gotchas that cost me time:
1. Argo CD moves to the next wave when the current wave is Healthy. A custom resource with no health check reports Healthy at once. So the next wave starts too early. Write a Lua health check for your CRs.
2. A CR in the same sync as its CRD can fail the dry run. Add SkipDryRunOnMissingResource=true to that resource.
3. Waves do not cross Applications. App A wave 5 still runs before App B wave 0. Use app-of-apps or ApplicationSets when you need order across apps.
4. Hooks stay in the cluster. Add hook-delete-policy: BeforeHookCreation, or you collect dead Jobs.
The annotation, on any resource:
metadata:
annotations:
argocd.argoproj.io/sync-wave: "1"
Start with two waves only. Add more when you can name the dependency that needs them. Every wave is a wait. Too many waves makes a slow sync that is hard to debug.
What is the highest wave number you run in production, and what made you need it?





