A few years ago I wrote about a setup I coded for myself for when I want to make paying my bills a tiny bit less painful. One thing I mentioned then was the primary selection. For those of you who don’t know it: under X.org, you can select a portion of text (for example by dragging the mouse over it) and then paste it in the same or another application with clicking the middle button. It is extremely useful for quick copy-and-paste operations where you do not have to issue a separate “copy” command (usually C-c, but often also found on mouse context menu). And by the way, Wayland also supports this.
Sometimes I find it useful to use it even without the mouse. Everybody knows how to select text using keyboard – one common way is by using movement keys with shift, but the Emacs way is to activate the mark with C-SPC and move the point using any of multiple ways Emacs gives us. The question is, however, how to paste the selected text without touching the mouse?
Well, it’s Emacs, so it’s enough to press C-h c and click the middle button to find out. It turns out that the command is mouse-yank-primary. Despite its name, it can be invoked without a mouse, either via M-x or by binding it to some key.
One important thing to mention here is that there is an option called mouse-yank-at-point. If it is nil (the default), the primary selection will be pasted in the place you clicked the mouse. I have it set to t, which means I can click anywhere in the Emacs frame and the primary selection will be pasted at point.
Of course, this is not going to be useful a lot of the time since the usual workflow with the primary selection is to both select and paste the text with the mouse, but if you need to do using your keyboard or from Elisp code, you know now how. (In fact, if you need to use the primary selection in Elisp code, you might want to check out the gui-get-primary-selection function, too.)
That’s it for today, see you next week!
As I’ve mentioned some time ago, I’ve been using Claude Code for some time now.
Now, a disclaimer is in place. I’m still a bit skeptical about the current “AI” hype – in particular, I really avoid using the term “AI”. I consider it a very misleading marketing gimmick. When non-technical people hear the phrase “artificial intelligence”, a computational model capable of generating more or less random sequence of letters which sometimes create a semblance of “understanding” or “intelligence” is probably not what they think. Well, I am really a layman, too – I have some extremely vague understanding what happens inside these “chatbots”, but other than that they seem a bit magical to me as well – but my point is, they are really closer to a giant spreadsheet with billions (or even more) of cells than to Skynet.
Anyway – even I have to admit that what Claude Code is able to do is pretty impressive. However, I quickly discovered that the OOTB experience is less than ideal. One of the easier ways to enhance Claude (and other LLMs, apparently) is by writing skills, which are basically reusable prompts or procedures for performing some tasks, written in natural language.
Compared to classic programming, writing skills is, well, a slightly different skill. Unlike hooks, they are not deterministic, and even though Claude has a way to “invoke” a skill directly, by typing a slash followed by the skill’s name, they can be invoked by a prompt which Claude interprets as suggesting using a skill, which is cool but much less certain.
From what I have learned so far, one of the biggest challenges when using LLMs in general and agentic coding in particular is “context management”. LLMs have very limited “attention span”, and giving them too much data makes them work worse. From skills perspective, this means that they should be as concise as possible. Two nice tricks that can help with that are: skill descriptions and dividing skills into several files. First of all, every skill file has a “description” field. All installed skills’ descriptions are preloaded at the beginning of the session, so providing concise descriptions clearly describing when Claude should use a skill is a crucial step. Besides, if a skill is really large – or has substantial parts which are needed really seldom – it may make sense to move these parts to separate files, and link to them from the main skill file. (Apparently, it is enough to tell Claude something along the lines of “When the user requests …, read the … file”.)
One problem with guidelines like this is that it is very difficult to know whether they are genuinely useful tips or just superstitions. The fact they are officially recommended gives some hope. Interestingly, Anthropic released a tool which helps with developing and evaluating skills. Reading through the files in its repo is a mind-blowing experience: the tool is itself a skill, and I have to say that the fact that it works (and I tried it out!) seems magical.
After all that intro, let me share one of the first skills I created (with help from Claude itself, of course). It is very simple in the sense that it only consists of one SKILL.md file, but it already proved itself to be very useful a few times on the first day I installed it!
It is often said that LLMs are generally very agreeable – they tend to flatter the user more than criticize them. Connected with the fact that the normal workflow is to tell the “agent” what you want done and expect obedience, there is a real danger that the only thing your coding agent will help you achieve is writing bad code faster. On the other hand, since LLMs were trained on a lot of written material, in particular describing good and bad practices, gotchas and pitfalls, it seems worthwhile to ask them if your idea is any good before implementing it and learning that it’s not the hard way.
So, here is the complete SKILL.md file for my assess skill.
--- name: assess description: > Assesses pros and cons of a user's idea, with a focus on weaknesses. Use when user asks to assess an idea. --- # Idea Critique Skill Before applying this framework, say: "Applying /assess framework". When asked to assess, evaluate, or critique an idea, apply this framework: ## Stance Default to skeptical. Assume the idea may have a fatal flaw and actively hunt for it before concluding it doesn't exist. This is not about being negative — it's about stress-testing so weak points surface early. ## Process 1. **Steelman first** — articulate the idea's best possible form before critiquing it 2. **Pros** — list genuine strengths with brief reasoning 3. **Cons** — list weaknesses; spend more effort here than on pros 4. **Weak points deep-dive** — pick the 1–3 most dangerous weaknesses and stress-test them hard. Ask: what would have to be true for this to fail? 5. **Verdict** — a honest one-line summary of where the idea stands 6. **Suggested pivots** — if flaws exist, propose concrete ways to address them ## Weighting Score each pro/con 1–3 for significance. Call out any single con scored 3 as a potential deal-breaker. Mark the scores as `[★☆☆]`, `[★★☆]` and `[★★★]`. ## Tone Direct and honest. Avoid hedging language that softens real concerns. The user wants signal, not comfort. --- Now apply this framework to the following idea: $ARGUMENTS
Note the use of $ARGUMENTS at the end – this ensures that I can tell Claude to invoke this explicitly, by saying /assess <my idea>.
I think the most astonishing thing about this skill is that it works really well despite being so short. At 220 words it takes up about 300 tokens, which is way smaller than, say, the aforementioned skill-creator (roughly 20k tokens!) – but is really useful.
Also, this is just the beginning. As of now, I have quite a few custom skills, and this one is one of the smallest (in terms of the word count). And despite the problems with the fact that they are, well, more what you’d call “guidelines” than actual rules, they are genuinely useful.
Recently I found myself killing and yanking more often than ever.
One problem with that is that the capitalization and punctuation of what I have yanked is often wrong. As a (pretty stupid) example, I might see the sentence “This is bad.”, and I might want to write another one: “He thinks that this is bad, and he’s right.” If I use kill-sentence (M-k) or backward-kill-sentence (C-x DEL), I have the whole This is bad. in the kill ring, but what I need to yank is this is bad (with lower-case “t” and without the period), so I need to make both changes after yanking. After several dozen such cases I thought, this is Emacs, I shouldn’t be doing this manually!
As is often the case, coding a feature where a text is transformed in a given way is pretty easy, but finding a good UI is not. I figured, however, that I could make it so pressing C-y for the second time could trigger the transformation. Yanking the same thing twice in a row does not happen very often, and if I really need to do it, I can just press C-y C-g C-y.
First, let’s enumerate the possible transformations. Making the first letter lower- or upper-case is the obvious one. Putting the whole yanked text in quotation marks is another. Stripping punctuation from its end is the last one I can think of. For now, I’ll just implement lower-casing the first letter and stripping punctuation.
If I were to code that several years ago, I’d use a hydra. Now that Emacs has transient built-in, I’ll try to use it – these days I tend to prefer built-in facilities over external packages. But first things first – let’s start with making C-y do something else than usual when pressed twice in a row. I could just advise yank (and if you read my blog regularly, you know I like advice!), but in this case, I don’t think this is the best idea. I have no idea how often yank is called from Elisp, and whenever it is, I don’t want to risk my code firing in such situations. So, I’ll choose the boring route and define my own command which I will then bind to C-y. This has one problem, though: in Org mode, where I might need this whole feature, C-y is bound to org-yank instead. For now, I’ll just ignore it and see whether I actually need my feature in Org mode, too; if so, I’ll just write an Org version of my enhanced yank and that’s it.
(defun mbork-yank-or-transform (&optional arg)
"Call `yank' or `mbork-transform-region-transient'.
The decision depends on whether `last-command' was `yank'."
(interactive "*P")
(if (eq last-command 'yank)
(mbork-transform-region-transient)
(yank arg)))
Now comes a harder part – defining the transient. I had a few issues with that. One was that I’ve never defined transients before, and that it was quite difficult for me to wrap my head around its manual. Luckily, by combining the manual, the Transient showcase, interrogating an LLM and trial-and-error, I was able to come up with a solution which actually worked:
(defvar mbork-transform-region-overlay nil
"An overlay used by `mbork-transform-region-transient'.")
(defun mbork-transform-region-make-overlay ()
"Highlight the region using `mbork-transform-region-overlay'."
(setq mbork-transform-region-overlay
(make-overlay (region-beginning) (region-end) nil nil t))
(overlay-put mbork-transform-region-overlay
'face
'secondary-selection))
(defun mbork-transform-region-delete-overlay ()
"Delete `mbork-transform-region-overlay'."
(remove-hook 'transient-exit-hook
#'mbork-transform-region-delete-overlay)
(delete-overlay mbork-transform-region-overlay))
(transient-define-prefix mbork-transform-region-transient ()
"Apply one or more transformations to the region."
[[("." "Remove punctuation"
mbork-transform-region-remove-punctuation
:transient t)
("l" "Lower-case the first letter"
mbork-transform-region-lowercase-first
:transient t)]
[("RET" "Quit"
ignore
:transient nil)]]
(interactive "*")
(add-hook 'transient-exit-hook
#'mbork-transform-region-delete-overlay)
(mbork-transform-region-make-overlay)
(transient-setup 'mbork-transform-region-transient))
I have a feeling that it’s not ideal – for example, exiting via ignore seems hackish, not to mention the hook stuff (which I needed to make sure the overlay is properly deleted, no matter whether the user exists via RET or C-g), but it works. The only thing remaining is to define the actual transformations – and that’s (of course) the easiest part, it’s just normal Elisp:
(defun mbork-transform-region-remove-punctuation ()
"Remove punctuation from the end of the region."
(interactive "*")
(save-excursion
(goto-char (1- (region-end)))
(when (looking-at-p "[.,!?]")
(delete-char 1))))
(defun mbork-transform-region-lowercase-first ()
"Make the first character of the region lowercase."
(interactive "*")
(downcase-region (region-beginning) (1+ (region-beginning))))
(By the way, the obligatory plug is that if “just normal Elisp” sounds like magic to you, and if you’d like to learn how you can easily modify Emacs to suit your needs like what I’m doing in this post, the best go-to source is the late Robert J. Chassell’s Introduction to Programming in Emacs Lisp – and if that is not enough for you, then my book about Emacs Lisp is envisioned as a next step after that. While it doesn’t cover transients, it consists of three progressively more complex features coded from scratch to production quality, with detailed explanations. Check it out!)
Now let’s just bind C-y to my command and I’m done!
# Don't do it like this. (bind-key "C-y" #'mbork-yank-or-transform text-mode-map)
Well, almost done. It turns out (rather expectedly) that Org mode is also derived from Text mode, so this overrides its normal org-yank binding, too. (Of course, if I ever need my command in Org mode, too, I’ll just write a similar mbork-org-yank-or-transform and bind it there.) Happily, there is a simple solution:
(bind-key [remap yank] #'mbork-yank-or-transform text-mode-map)
This way my command replaces any keybinding normally mapped to yank, including, for instance, S-<insert> etc., but leaves org-yank alone.
And that’s all there is to it. The only thing that’s left is that I’ll probably extend the transformation set over time – but that is another story.