Clone 3rd party dependencies for AI Coding Agents
Published on 2026-03-28
I've previously did some work on the clickhouse-activerecord
gem and I wanted to share a tip I came across for helping coding agents. I came across this tip while
on x. It came from Michael Arnaldi, who is the founder of the company
behind Effect, a Typescript library. Effect is a very different way of
writing Typescript and newcomers were messaging him asking for the best way to solve problems with Effect.
His answer to these questions was to clone Effect into their project and let the agent read Effect's source code.
This is a particular nuance of the Typescript ecosystem where not all libraries ship their full source code;
sometimes the source is shipped in a minified manner and only the public API is accessible through the code
in node_modules/. While we don't have that issue in Ruby on Rails, in my particular
case, I was working on a gem which is an adapter to ActiveRecord so there isn't a need to have the ActiveRecord
code in the gem itself.
If you find yourself working on a project interfacing with 3rd party dependency and the coding agent is struggling
to help, clone that dependency into your project. In all my projects I have a tmp/ directory with
everything inside it added it .gitignore and that is where I'll clone these dependencies into. You'll want to add
explicit instructions prompt to look in tmp/<dependency> because by default the coding agent will ignore it. I hope
this helps on the next project you work on and if you're interested in a real world application of this approach, I've
written up how I used it to add a feature to the clickhouse-activerecord gem.
Practical Example - clickhouse-activerecord#
At work, we have a handful of monkey patches to the clickhouse-activerecord gem and we're currently stuck on
an older version of the gem due to incompatible changes. I made it a goal for myself to get us onto the latest
version of the gem and remove as many of the patches as possible. Some of these patches are candidates to be
upstreamed to the gem and others were added due to issues we ran into. The first one I aimed to tackle was a patch
in our testing suite to use database-cleaner to truncate the ClickHouse tables. Using database-cleaner works, but we're currently maintaining a hardcoded list of tables in test_helper.rb to skip specific tables that cannot be truncated.
ClickHouse has a set of table engines that cannot be truncated and the gem was not taking that into account. Those
engines can be seen in the Truncate Table documentation.
Additionally, one other type of engine that cannot be truncated is a
Dictionary, which isn't exactly a table but behaves like one and
we use them a lot at work. Now that we have the
background established, lets set out on figuring out how to implement this. Because we have the whole Rails
repository in our tmp/ folder, we should have no problem looking up how other database engines handle truncation.
I can ask a question like this.
How does the mysql adapter in ActiveRecord handle truncation? Look in
tmp/railsto find the ActiveRecord code.
The answer I got pointed me exactly where I needed to go.
Here's how the MySQL adapter handles truncation:
Two distinct paths
truncate/truncate_tables(abstract base indatabase_statements.rb) ...empty_all_tables(MySQL-specific override inabstract_mysql-adapater) ...
The entrypoint to the truncation is
ActiveRecord::ConnectionAdapters::DatabaseStatements and it's #truncate_tables method.
My initial approach was to override #truncate_tables and add in our special cases. However, as I was reading
through the code in #truncate_tables, I noticed it was calling out to another method, #build_truncate_statements.
A quick search for where #build_truncate_statements is defined showed there is a definition in the
DatabaseStatements class as well as an override in
ActiveRecord::ConnectionAdapters::PostgreSQL::DatabaseStatements
class. After taking a look at the Postgres override, it was clear all I needed to do was add my own
#build_truncate_statements to clickhouse-activerecord and that is what I did. The full Pull Request for my
changes can be found here,
SchemaStatements#truncate_tables skips engines that cannot be truncated.
With the change, truncation will now work out of the box on all types of ClickHouse tables.
Conclusion#
The harder part in programming, in my opinion, is first discovering what I don't know about the problem I'm facing.
Once that discovery has happened, building the solution is straight forward. If I had known about the
build_truncate_statements method from the get go, the amount of time this PR took would have been greatly reduced.
However, with this approach of having the cloned dependency in my tmp/ directory, I've greatly reduced the amount
of time spent on that discovery.