Operations 26w35

monkey-id
Operations 26w35

This session is for operational work during this week. Address (monkey-task-context) items directly, one subheading in the NOTE is for one item.

Fix mapping-pipeline deployment due to SSM parameter

https://github.com/FindHotel/mapping-pipeline/actions/runs/32779045038/job/97599196109

Fix Dependabot failure in content-pipeline

https://github.com/FindHotel/content-pipeline/actions/runs/32709801786/job/97378566903

Fix content-pipeline deployment due to SSM parameter

Same as above for mapping-pipeline.

This parameter should not be used, part of Migrate Content system to Keypair auth in Snowflake. Check that it is not in use and remove the whole parameter.

Remove pagerduty SSM parameters from mapping-pipeline
wt
(◊git-status "~/.wt/mapping-pipeline_remove-pagerduty-parameters")
PR
Remove unused SSM parameters ⋅ mapping-pipeline#2070
AWS_PROFILE=fh-meta AWS_REGION=eu-west-1 \
aws ssm describe-parameters --page-size 50 | gron | grep Name | grep sovitin | grep pagerduty
Remove cms-update-hotel

With migration to OPUS, (◊grep 'content-pipeline "cms-update-hotel") is probably no longer needed - it calls Hotel API for hotel content.

Check in the ~/.vio/OPUS repository.

If confirmed, cleanup content-pipeline and mapping-pipeline repos.

PR has been merged, deploy on staging envornment, and monitor production deployment.

CONTENT-4186 Fix img-proxy source image fetch timeoutsCase
related
ImgProxy

Redeployed obfuscated-proxy v1.4.0, check if that fixed. No.

CONTENT-2793 agd_duplicated_hotel_feedback expiredCase PR

The PR mapping-pipeline#1981 was closed due to stalliness. Need to address comments and merge it.

CONTENT-2793 - mapping-prod, AGD feedback CSV

  • Root cause (10th confirmation): bucket-wide 180-day S3 lifecycle rule expired agd_duplicated_hotel_feedback/latest.csv. Mitigated 2026-06-10; last 12 runs SUCCEEDED.
  • Still open: lifecycle rule unscoped, loader unhardened. Hard deadline 2026-12-07 — file expires again.
  • Recommend: close as mitigated, stop recurring re-checks, file follow-up before deadline. Owner ping to hguo@vio.com unanswered since 06-15.
Remove ECS infrastructure from obfuscated-proxy

Obfuscated Proxy was migrated to EKS, old ECS IaC is not relevant. Cleanup.

Monitor if upgrade to Spark 4 works
Cleanup usage of content.interface.placeStory
use role content_dbt_prod;
use schema content.content_prod;
alter table content.content_prod.place rename to place_hco;
create view content.content_prod.place as select * from content.content_prod.place_spark;

Content Squad announcement:

  • Old content.content_prod.place table (HCO-based) has been renamed and considered private
  • content.content_prod.place now a view over production-ready table developed within PI: Better Geographic UX | Notion.

Datadog renamed Case Management to Work Management

We use Datadog Case Management at $WORK for managing failed batch jobs. When a job fails, it sends event to EventBridge then to Datadog Events, then a Monitor captures and opens a new case, providing all the details of failure (links, names, timing, basically what comes in the event). Automation workflow archives duplicated active case by title, so sequential daily runs only lead to the first case. Works really well, about 4000 cases have been created in the last 6 month of usage. AI agents are checking open cases on schedule and do root cause analysis and resolve cases (open PRs with fixes) semi-autonomously (Claude became lazy recently).

Today I noticed that Datadog renamed Case Management to Work Management, and it changes premise quite a lot. Do you remember Slack mission "Slack - where work happens" - well, often it's true, but when it is true, it means somebody doesn't do their real work. If we have a product "Work Management", then, well, why don't we use it to manage work, and manage work in Slack/Notion/Shortcut/Github. Fifth place to manage work. Thank you very much, dear Datadog, you went from a strong concept of a funnel – Alert → Case → Incident – into vague "Work Management"

Case Management API has been always not pleasant: heavy relying on UUIDs, lack of public API methods - can't link cases, can't READ COMMENTS - yes, you can POST a comment, but you can't read it back. To overcome these limitations, I had to check what Datadog UI is doing and wrap it into datadog-mcp-server.

What has changed in the API side of things with this renaming? Absolutely nothing, Work Management doesn't exist nor in API reference nor in the API requests, they still go to https://app.datadoghq.com/api/v2/cases.

textlog

monkey-id
textlog.el

A quiet, text-only microblogging platform, open-source, no JS.

HN
Show HN: textlog
github
stagas/textlog
website
https://textlog.cc
(no term)
(◊ff 'velpa "textlog.el")

I created handle @hotter and ./src/textlog.el package to send regions to textlog.

Microblogs, related to Textpod.

Another self-hosted microblogs and related:

Implement textlog.el

~/.velppa/velpa/textlog.el

Use new API methods

textlog-post should be using POST /posts method.

Implement textlog-reply command

It should get recent replies to the current user in completing-read.

Upon selection a message, store its id, then post new message (read interactively).

Textlog replies flow

Assign CapsLock to RightControl

I'm using Handy.app (cjpais/Handy) for text-to-speech and hold-to-speak functionality. Which button to use? Right Option rarely used, but I do use it as Hyper key in Emacs, in particular {H-RET} calls visit-source (visit-source.el).

Right Control also rarely used and does exists on my Keyboardio Model 100. But, it turned out macOS remaps CapsLock to Right Control from the SystemSettings.app.

260804--keyboard-remapping__macos.png

I need some remapping then, for internal keyboard only:

  • CapsLock to Left Control
  • Left Control to Right Control

To achieve that, store the plist to ~/Library/LaunchAgents/com.local.keyboard-remap.plist file.

To rebind live without reboot, run hidutil commands manually. In SystemSettings.app set default CapsLock binding (CapsLock to CapsLock).

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.local.keyboard-remap</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/sh</string>
    <string>-c</string>
    <string>
      /usr/bin/hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000039,"HIDKeyboardModifierMappingDst":0x7000000E0}]}';
      /usr/bin/hidutil property --matching '{"VendorID":0x0,"ProductID":0x0}' --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc":0x700000039,"HIDKeyboardModifierMappingDst":0x7000000E0},{"HIDKeyboardModifierMappingSrc":0x7000000E0,"HIDKeyboardModifierMappingDst":0x7000000E4}]}'
    </string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

claude-pager

On <2026-06-03 Wed> I somehow bumped into idea to use emacsclient as EDITOR in Claude Code.

Turns out CC respects EDITOR env variable, either from environment or configured in ~/.claude/settings.json:

{"env": {"EDITOR": "emacsclient", "VISUAL": "emacsclient"}}

Even if [Feature Request] Allow configuring external editor for Ctrl-G prompt editing · Issue #18990 · anthropics/claude-code is still in open.

In that issue I spotted this project: gradigit/claude-pager. Fast C transcript pager for Claude Code: no blank Ctrl-G screen, clickable links/files, queued prompt composer. And its sister editor: gradigit/turbodraft.

Tried both. Turbodraft - I don't need another text editor rather than Emacs, so skipping it. But claude-pager looks useful, so I forked it.

First, I wired Emacs into claude-pager; so that it renders transcripts in both CC screen when it waits for the prompt + adds it to Emacs temporary buffer.

This mostly solves clunkiness of copying from claude terminal into Emacs and back - now I press {C-g} in claude and continue editing in Emacs.

Related to Agent SDK billing and parting ways with agent-shell.

This is how my env block looks like in ~/.claude/settings.json.

{
  "env": {
    "EDITOR": "/Users/pavel/.velppa/claude-pager/bin/claude-pager-open",
    "CLAUDE_PAGER_EDITOR": "/Users/pavel/.velppa/claude-pager/emacs/claude-emacs-prompt",
    "CLAUDE_PAGER_EDITOR_TYPE": "gui"
  }
}

{C-g} in claude opens claude-pager-open that generates transcript and pastes it into both terminal and to the temp file to edit in Emacs, then runs claude-emacs-prompt shell file that calls elisp file which loads into the buffer, assigns keybindings etc.

Setup involves adding hooks:

SessionStart hook:
     26:            "command": "/Users/pavel/.velppa/claude-pager/shim/save-session-transcript.sh"

Then I rewrote the binary from C to Zig. Rewrite used Superpowers to develop a spec first, then launch a series of agents. It took 4+ hours for CC to finish rewrite, it was ready in the morning. It used all extra usage (42 EUR) in fast mode in first 20 minutes.

7000 loc in C => ??? in Zig.

Now I understand the C well.

Another interesting project from the same author:

  • gradigit/confetti - Lightweight confetti animation for macOS — fire colorful confetti from your screen corners

Copy buffer-name with easy-kill

easy-kill Emacs package allows killing multiple things, switching between them on the fly. I use it to quickly grab the buffer-file-name (full path or file name only), using {M-w b}.

github
leoliu/easy-kill

Keybindings:

{M-w} without active region
copy current line, same as {x y} in meow-normal-mode
{M-w C-w} without active region
kill current line, same as {x s} in meow-normal-mode
{M-w b}
copy current full path to buffer-file-name
{M-w b 0}
copy current buffer-file-name
{M-w b -}
copy current directory

On <2026-06-04 Thu> I added {M-w B} to copy current buffer-name, useful to paste into Claude Code (running under ghostel for me).

Here's the configuration block:

(use-package easy-kill
  :config
  (keymap-global-set "<remap> <kill-ring-save>" #'easy-kill)
  (defun easy-kill-on-buffer-name (_n)
    "Get current `buffer-name'."
    (if (easy-kill-get mark)
        (easy-kill-echo "Not supported in `easy-mark'")
      (easy-kill-adjust-candidate 'buffer-name (buffer-name))))
  (add-to-list 'easy-kill-alist '(?B buffer-name)))
  1. Define function easy-kill-on-buffer-name.
  2. Add binding to 'easy-kill-alist.

Superpowers

An agentic skills framework & software development methodology that works.

github
obra/superpowers
CAVEMAN vs Superpowers

Stacking: orthogonal. Run both → superpowers process + caveman terse output.

caveman

Purpose
output compression, cuts tokens ~75%
Affects
how Claude speaks — style only
Skills
caveman, caveman-commit, caveman-review, caveman-compress, caveman-stats, caveman-help
Agents
cavecrew-investigator, cavecrew-builder, cavecrew-reviewer (compressed output)
When active
persistent mode (every response)
Token cost
saves tokens

superpowers

Purpose
workflow scaffolding, methodology + process skills
Affects
what Claude does — multi-step procedures
Skills
brainstorming, writing-plans, executing-plans, test-driven-development, systematic-debugging, subagent-driven-development, dispatching-parallel-agents, using-git-worktrees, requesting-code-review, receiving-code-review, verification-before-completion, finishing-a-development-branch, writing-skills, using-superpowers
Agents
none direct
When active
invoked per-task (Skill tool)
Token cost
spends tokens (more thorough flows)

caveman

github
JuliusBrussee/caveman
HN
Caveman: Why use many token when few token do trick | Hacker News
YouTube
No way this actually works - YouTube - ThePrimeTime

Why use many token when few token do trick — Claude Code skill that cuts 65% of tokens by talking like caveman.

I tried it on <2026-04-11 Sat> on Mac Mini 2024 and on Mac Book Pro M1.

claude plugin marketplace add JuliusBrussee/caveman && claude plugin install caveman@caveman
claude plugin uninstall caveman@caveman && claude plugin marketplace remove caveman

Uninstalled after reading HN comments. Installed again recently.

Caveman in gptel

Add caveman as a gptel directive:

(setq gptel-directives
      (cons '(caveman . "CAVEMAN MODE: Drop articles/filler/pleasantries/hedging. Fragments OK. Short synonyms. Pattern: [thing] [action] [reason]. [next step]. Keep full technical accuracy. Code unchanged.")
            gptel-directives))

Select with C-c C-d in gptel buffer.

HN comments summary

A developer created "Caveman," a Claude Code skill that forces the AI to respond in simplified, caveman-like language to reduce token usage by approximately 75%. The author clarifies this is mostly a joke and targets visible output (removing preambles and filler text), not the hidden "thinking" tokens that improve performance. They acknowledge the ~75% claim needs proper benchmarking and note that the skill doesn't affect code quality itself.

The Hacker News community is highly skeptical, with many arguing that tokens are "units of thinking" for LLMs—reducing them could make the model dumber by limiting its reasoning capacity. Critics point out that chain-of-thought reasoning requires verbose output, and forcing concise responses may degrade performance. However, some find the concept useful for cutting through verbose AI responses, comparing it to telegram-style communication or noting that similar concise prompting can work without harming quality for simple tasks. The debate centers on whether this actually saves meaningful costs versus potentially sacrificing accuracy.

SafariTabs.app v0.2.0

On <2026-05-07 Thu> I do several improvements to SafariTabs.app.

  1. Dragging swimlanes, so I can rearrange them to follow Spaces 3, 4, 5.
  2. Rename windows, mine are "Personal", "Work – Tech", "Work – Communications"
  3. Auto-sized swimlanes: each column takes 1/3 of the app window, capped at 1/6 of the current display — so a half-screen window always fits 3 columns and a maximised one fits 6, on any resolution.
safari-tabs.png