From Internal Memo to Public Story: Building a Content Agent for VCs

I was speaking to a VC last month and they mentioned their marketing strategy is to publish their investment memos as blog posts.

It’s really one of the best ways for a VC to grow their brand. Bessemer and other big funds do it often.

The only problem is it takes time. Smaller VCs don’t have the bandwidth or resources to turn their private investment memos into public ones.

The VC I spoke to said it took them hours to remove sensitive information from their investment memos, and rewrite them in a consistent style for the blog. So they weren’t able to do it consistently.

Well, AI can solve that. Today, we’ll build an AI agent that automates this process using Claude and modern web scraping tools.

The Solution

I built a fully autonomous agent for the VC that gets triggered when they create a new investment memo and automatically publishes a draft post to their blog. This entire workflow is invisible and sits inside their operations.

For the purposes of this blog post, I’m going to simplify it. Instead of automatically triggering it (since I don’t know what your operations look like), we’ll create an interface with Streamlit where you can manually trigger it.

Our interface will:

  • Accept investment memos in various formats (text, PDF, DOCX)
  • Use Claude to identify and remove sensitive information
  • Scrape the company’s website for public information
  • Generate a polished blog post matching your writing style
  • Provide easy export options for the final content

Implementation

Setting Up the Project

This entire project with code is open source on my GitHub for you to clone and run locally. After that you can modify the code and customize it to your fund.

You can also take the core agent logic and have it triggered by your existing workflow and even publish to your website.

I’ve set up the files with this structure:

memo-converter/
├── requirements.txt
├── README.md
├── .env
└── src/
    ├── __init__.py
    ├── main.py
    ├── interface.py
    ├── fetcher.py
    ├── sanitizer.py
    └── generator.py

The Interface file is the code for our Streamlit interface. You can upload your investment memo to it, enter the URL of the company you’re investing in, and also upload a blog post whose style you want to match (ideally one of your own).

Fetcher fetches more information about the company you’re investing in. Sanitizer cleans your investment memo. Generator creates the blog post.

At the end of it, the Interface display the final post.

Building the Interface

The interface.py file is where we’ll create our Streamlit interface. Streamlit is an open-source Python package that makes it easy to build visual interfaces for data and AI.

Our interface will provide a clean, intuitive way to input memos and reference content. As you can see in the code, we use tabs to organize different input methods and provide document preview functionality. We’re also going to add a little slider to control how long we want the final blog post to be.

We’re allowing document upload so we need a function to help us read this:

Sanitizing Sensitive Information

The first thing we want to do when our interface accepts a new investment memo is sanitize it and remove sensitive information.

If you were building this as an agent, you would skip the interface and trigger the agent here.

Instead of using a rule-based approach, we can just ask an LLM (Claude in this case) to read through it, remove sensitive information, and return a clean version.

You can use any other LLM. It’s probably more optimal to use a smaller and cheaper model like GPT 3.5 turbo, but I just prefer Claude when it comes to working with content.

You’ll find this code in sanitize.py:

Gathering Public Information

You’ll notice our interface accepts a URL for the startup you’re investing in. We use Firecrawl to scrape the company’s public website and get more information about it to add to our marketing post.

If your investment memo already contains a lot of information about the company, you may not even need this.

All this code goes in the fetcher.py file:

Generating the Blog Post

Ok, now we have all the pieces we need to generate our final blog post. We got public information about the company from the fetcher, a clean investment memo from the sanitizer, and a reference memo from the interface.

Using another Claude instance, we can generate the final blog post, using the reference memo to match your writing style.

As you can see in the generator.py file, most of the code is really just a well-crafted prompt:

Display Blog Post and Allow Document Export

Back in our interface.py file, we want our blog post to display in the interface. Again, if you were building this as an autonomous agent, you can skip this and directly publish to your website.

Here’s the function:

If you want, you can also add options to export it as a document:

Tie It All Together

And that’s it!

Our main.py file ties it all together:

Running the Application

All the instructions to clone and run the code are on my GitHub. To use the application:

1. Set up your environment variables:

ANTHROPIC_API_KEY=your_anthropic_api_key
FIRECRAWL_API_KEY=your_firecrawl_api_key

2. Run the Streamlit app:

streamlit run src/main.py

Benefits and Results

This application provides several key benefits:

1. Time Savings: What used to take hours can now be done in minutes

2. Consistency: Generated posts maintain your writing style across publications

3. Safety: Reduced risk of accidentally sharing sensitive information

4. Flexibility: Support for various input formats and export options

5. Scalability: Easy to process multiple memos efficiently

Conclusion

Ok that was a lot to take in but you can simply clone my repo and run the code yourself. Just don’t forget to add your API keys!

The modular architecture makes it easy to enhance and customize the application as needs evolve. As I mentioned before, you can turn this into a fully autonomous agent.

If you need any help or advice, or you want to set up agents at your fund, book a call with me.