Reflections on Claude Code


I’m generally a pretty slow adopter of new tech, but in the case of Claude Code, the groundswell of support and enthusiasm was simply too strong to ignore. Having now spent some months exploring how I might work with it, it feels to me like easily the biggest step change, in terms of utility, of any development in the LLM era. For many people, ChatGPT was probably as significant, but that was arguably more about public awareness, rather than dramatic progress. Claude Code, by contrast, truly feels transformative, and it’s honestly shocking that it works as well as it does!1

As a starting point, I was initially surprised by how difficult it was to find a simple and clear guide on setup and reasonable usage, in terms of setting things up in a relatively safe and stable fashion. Anthropic itself provides some amount of documentation, but the range of different opinions out there seems quite vast. In part, this is par for the course with respect to fast moving technologies, but it also feels like there is wide variation in how much effort people are willing to invest in their infrastructure, and how much risk they are willing to tolerate.2

Being somewhat on the paranoid side, I was hoping to find a way of setting things up that would provide reasonable protection against certain risks. Based mostly just on my own amateur threat analysis, it seems to me like there are basically three major types of risks to consider:

  1. First is the risk to local files. Claude’s whole job is to modify these, but one might want to limit the set of files that it can touch. To some extent this can be managed by containerization, although that only provides one level of security, and is not really the purpose for which containers were designed.3
  2. Second is the risk of losing control over what information Claude transmits to an external service, or downloads from the web. This can be managed by controlling the firewall, but it is a fine balance between utility and risk. Although the present danger is presumably low, it seems like there is some real possibility of someone setting up a malicious site that would try to attract visits from coding agents, and coax them into sharing private information, or something along those lines.4
  3. The third and probably most serious threat seems to be whatever risks comes from the code that Claude produces, rather than any actions that Claude itself takes. This is not so different from the risks involved in getting coding help from any earlier version of this technology, such as a chat model, or something like Codex, but the sheer volume of code which Claude Code can help produce, and the ease of doing so, means that this threat seems to grow by sheer scale. As with the first risk, this can be mitigated by only running that code in a container, but that involves potentially annoying limitations, especially during development.

Some have argued that the best mitigation is simply to carefully check every line of code that Claude produces, but this seems to expect rather a lot of our ability to detect potential threats in code, not to mention the time cost of doing so. Beyond that, some sort of external model for threat detection is probably the right thing to use, but pretty quickly we are in to a world where we are relying perhaps too heavily on models for all aspects of our security.

Personally, I resigned myself to setting up Claude Code in a container as a relatively simple and minimal layer of protection, and one that did not require depending entirely on Anthropic’s own safeguards. I opted to use the devcontainer extension in VSCode, while recognizing that this is of course not a bulletproof option. Technically, this was quite easy to set up, except for the small matter of actually of connecting it to my account. Although I eventually figured it out, it was more challenging than I expected to figure out how to get Claude Code in the container to use my Anthropic subscription, as opposed to API credits (which seemed to be the default that I was being funneled towards).

Very quickly, I discovered some of the friction that exists with such a set up. In the container, Claude only has access to whatever you set up for it, which means no python, and no access to websites that would allow it to install python. Claude will thrash in these early moments, trying to come up with some solution that will allow it to do more. Giving it access to a python installation is straightforward, but letting it install packages (which are basically essential to be more than minimally helpful) seems to require giving it firewall access to pypi or similar, which means allowing it to potentially install arbitrary packages. I couldn’t find an easy way to simply give it a whitelist of packages that are allowed, and even if I did, it wasn’t clear to me how much of that would be operationalized as an actual hard constraint, versus something more like instructions that one hopes it will follow.

This seems to be a central dilemma in a lot of the reliability concerns around this technology. Because models are in most cases very good at following instructions, people tend to reach for solutions that are based around simply providing guidance (perhaps strongly worded) in a configuration file. But there is nothing about this that provides any guarantees, and so while such an approach might have great practical utility, it will not necessarily prevent worst case scenarios.

The actual design of Claude Code does of course provide multiple layers of abstraction and protection, based on analysis of the leaked code. Everything is operating via a central language model, which can only call tools that you give it access to, and it is possible to require that it obtain permission before actually executing anything. A concern, however, is that it’s far too easy to slip into a causal laziness around the risks, and far too hard to properly assess the threats associated with any particular function call.

Overall, I was pretty happy with my set up, but for certain things I was trying to do, it quickly became painfully difficult to actually run all that I wanted to test out inside the container. As much as I hate to admit it, I pretty quickly switched to placing way more trust than I feel like I should be in the system, and pretending that I am somehow capable of detecting security risks by simply looking at the code that it is producing. Although I think it is basically a mistake, I found myself calling scripts that Claude had written without any containerization (accepting the third type of risk), simply because I wanted to test out a GUI, or similar. I felt quite confident in doing so, in part because there was nothing particularly sensitive involved, because I had at least somewhat limited damage using user permissions, and because I had at least minimally reviewed the code. But also feel like this is not an acceptable solution, and I’d like to eventually come up with something better.

A big part of the reason for my carelessness here, other than wanting to keep up with everyone else, is that I had underrated the extent to which using Claude Code is simply addictive. In fact, it honestly feels like the most addictive technology I have used since something like the last Civilization game that I played. I’m not sure if everyone would feel the same way, but the degree to which it gives one the power to imagine some small change or feature, issue a brief request asking for what you have in mind, and then have this be created for you within a few minutes, creates an incredible sense of possibility. Naturally, things don’t always end up quite as you expect or intend the first time, but that itself is a huge part of the draw. Being able to produce an imperfect but tangible implementation almost instantaneously gives you yet more issues to think about, design around, and request modifications to, feeding more trips through the core gameplay loop. As I wrote on Bluesky (slightly tongue in cheek), it’s wild how quickly Claude Code lets you progress from rapid prototyping to feature creep.

Truly, there is something here that is not so far from artistic creation. I can’t quite place it, but I am reminded of some scene from a science fiction film, in which a character is “designing” a physical object by asking for iterative updates, much like many of us are now doing in code. In the fictional portrayal I can’t quite recall, it seemed silly and almost embarrassing. In practice however, it feels wondrous and empowering. I had assumed that everything would have a tendency towards generic similarity, which in some cases it does, but in practice, it feels like the main capability being empowered is coming up with a very specific and individual variant of something, even if it already exists in another form.

Part of the reason I think this works is that by lowering the cost of code production, we have suddenly enabled the creation of things that would otherwise be far too costly to be worth it, including highly individualized solutions to possibly fairly specific problems. It’s hard to say how this will play out, but my sense right now is that it will gradually become far less worth it to learn systems that have been created by others, and far more effective to simply come up with your own specific solution that meets your specific needs, at least for certain types of problems. While many people will of course happily share their creations with others, the potential for widespread security flaws might also mean that it becomes increasingly unacceptably risky to try out code from a random GitHub repo, and therefore also safer to simply create your own solutions.

My proof of concept for this is also the first thing that I have made using Claude Code which feels to me like it is truly useful. Permit me a bit of backstory here: Although this ended up being delayed by one year, there is a new federal mandate that all course materials need to be made accessible, up to some standard that has been set by the government. Although what that means in practice is a complicated and thorny issue that deserves its own post later, the immediate effect is that all of us in education have been scrambling to update our course materials to at least minimally meet certain standardized accessibility requirements (and hopefully do even better).

Although some of this is fairly easy (e.g., making sure each slide has a title), a specific pain point is PDFs, which are inherently not particularly accessible, especially if you are using something like a scanned book chapter from a book that does not have electronic access. For new course materials, a simple solution is simply not to use PDF as a format at all, (although I do think they are useful for many people), but for older materials, which might still be quite helpful, some other solution is needed.

Because the University of Michigan is a massive institution, they have mostly been trying to find extremely generic hammers that could be used to aid with this, such as the Panorama system in Canvas that checks course materials for compliance. For PDFs, their suggestion was to use Adobe Acrobat to make PDFs accessible if necessary. Having tried it out, I can safely say that Acrobat is an abysmally bad solution. Perhaps I’m just using it wrong, but with my best efforts, its attempt at OCR was embarrassingly bad, and the ability to edit that OCR was practically non-existent, since there was not even an easy way to see what it said.

Happily, there are now many excellent OCR systems out there, with a range of different computational needs, costs, and affordances. What I really wanted was a way to extract the text and images from PDFs (using OCR and layout analysis), check those for errors, and then integrate everything back into a more accessible format, like Markdown or HTML. The specific OCR models that exist have gotten better and better, but the focus has mostly been on the quality of the text recognition, rather than the integration. After trying out a few solutions, I decided that this would be a perfect use case for Claude Code.5

I’ll spare the details around development, except to say that I set myself a goal of seeing if I could have a functional prototype within 24 hours after conceiving the idea, so that I could share it with some students at an event I was scheduled to speak at. Honestly that was far too generous of a timeline, as I easily met that without hardly trying. I ended up basing things around Surya, which is an excellent and relatively light-weight solution (better than tesseract, but less heavy duty than something like OlmOCR). I explored just using the Claude API instead, but ultimately found that it did not perform as well in key ways, specifically with respect to accurately locating bounding boxes, which are important for easy human verification.

Having completed a quick but functional prototype, I then spent more time than I would like to admit refining and expanding how the system works. While others’ taste might differ, the key idea that makes this system work in my mind is highly interpretable and detailed intermediate representations. Extracting figures, tables, and other regions can easily be done with bounding boxes, and these can easily been seen and edited in place using a simple GUI. OCR can be run line-by-line, which allows for easy verification by comparing the OCRed text directly below the line. Finally, Markdown provides a simple but sufficient format for flexible assembly, providing headings, paragraphs, lists, enumerations, figures, tables, captions, and endnotes. These are all easy to edit in any Markdown editor, before converting to a final HTML document. Ultimately, this solution is similar to PaddleOCR, but with more ability to intervene at intermediate steps.

In case anyone has similar use cases for converting PDFs to Markdown or HTML, the toolkit I created is available on GitHub. In accordance with my comments above, it was produced with the heavy assistance of Claude Code, so there are no guarantees with respect to security vulnerabilities or regular updates, but it does honestly feel to me like quite a useful system, either to used directly, or for someone else to extend. There are still many more features that I would love to integrate into this, but for the moment, having met my specific needs for this particular use case, I should probably return to directing my efforts elsewhere.

That’s one case where I was able to solve a specific problem with a custom solution, but there are infinitely more. For me, the ability to almost instantaneously create GUIs in particular is something I find enormously useful, especially for things like data exploration and annotation. Other uses, like more sophisticated coding or designing experiments still feel a little more brittle to me, but of course everything is progressing just about as rapidly as we can imagine it.

Probably never has there been a better demonstration of the instability of technology, given how quickly things continue to evolve, and how much one has to work just to maintain a usable setup. Taking a longer view, I do worry that we are ultimately headed toward some significant security flaws in our software world in the not too distant future, but it’s clearly going to be an ongoing arms race between offensive and defensive models. More generally, it seems like most people are counting on a kind of security by obscurity, simply hoping that any serious problem will affect someone else first, and that any systematic failure will be too widespread to worry about.

I can’t say that any of that is especially comforting, but in the meantime, there is a whole wide world of software to direct our systems to create!


  1. I do wonder to what extent the agentic coding research community feels the same way about Claude Code as I did about ChatGPT. Is this ultimately just a slightly better and much better known version of systems that already existed? Or did Anthropic pull off something special by getting this to work as it does? ↩︎

  2. If nothing else, the Moltbook example showed many people’s almost painful disregard for security and privacy concerns. ↩︎

  3. Indeed, if I understand correctly, Claude Mythos supposedly broke out of a container that Anthropic itself set up! ↩︎

  4. Indeed, a recent paper from Deep Mind proposed an extensive typology of risks of this kind. ↩︎

  5. In retrospect, probably the best existing option that I have found is PaddleOCR, which does seem to do a lot of what I have in mind, but I ultimately greatly prefer my solution, which provides the affordances I want where I want them. This is the clearest example to me of why custom solutions may end up becoming more common going forward. ↩︎