惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Tailwind CSS Blog
C
CERT Recently Published Vulnerability Notes
P
Proofpoint News Feed
Vercel News
Vercel News
博客园 - 三生石上(FineUI控件)
IT之家
IT之家
Help Net Security
Help Net Security
月光博客
月光博客
N
News and Events Feed by Topic
Cloudbric
Cloudbric
博客园 - 司徒正美
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tenable Blog
The Register - Security
The Register - Security
The Hacker News
The Hacker News
I
InfoQ
The Last Watchdog
The Last Watchdog
MyScale Blog
MyScale Blog
Schneier on Security
Schneier on Security
WordPress大学
WordPress大学
小众软件
小众软件
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
宝玉的分享
宝玉的分享
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
K
Kaspersky official blog
L
LINUX DO - 热门话题
N
News | PayPal Newsroom
F
Fortinet All Blogs
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Security @ Cisco Blogs
Recorded Future
Recorded Future
大猫的无限游戏
大猫的无限游戏
H
Help Net Security
Google Online Security Blog
Google Online Security Blog
S
Schneier on Security
C
Cisco Blogs
N
News and Events Feed by Topic
V2EX - 技术
V2EX - 技术
Latest news
Latest news
PCI Perspectives
PCI Perspectives
T
The Blog of Author Tim Ferriss
P
Palo Alto Networks Blog
T
Tor Project blog
Project Zero
Project Zero
云风的 BLOG
云风的 BLOG
Webroot Blog
Webroot Blog
Attack and Defense Labs
Attack and Defense Labs
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org

Pierce Freeman

A browser for agents | Pierce Freeman The grey market of podcast appearances The way I travel | Pierce Freeman Fixing slow AWS uploads | Pierce Freeman Local tools should still use vaults We solved scratch content first Starting a podcast in 2025 Being late but still being early Automating our home video imports Adding my parents to tailscale A deep dive on agent sandboxes Language servers for AI | Pierce Freeman My simple home podcast studio We need centralized infrastructure | Pierce Freeman Coercing agents to follow conventions using AST validation My unified theory of social selling My personal backup strategy | Pierce Freeman July updates to the homelab How the KV Cache works httpx is the right way to do web requests in Python Reputation is becoming everything | Pierce Freeman Building a (kind of) invisible mac app Updated knowledge in language models Making an ascii animation | Pierce Freeman How speculative decoding works | Pierce Freeman Under the hood of Claude Code Doing things because they're easy, not hard Speeding up sideeffects with JIT in mountaineer Firehot for hot reloading in Python Misadventures in Python hot reloading How text diffusion works | Pierce Freeman The tenacity of modern LLMs The ergonomics of rails | Pierce Freeman How language servers work | Pierce Freeman Just add eggs | Pierce Freeman Unfortunately SEO still matters | Pierce Freeman The futility of human-only web requirements Setting up Input Leap | Pierce Freeman Checking in on Waymo | Pierce Freeman The react revolution | Pierce Freeman Speeding up many small transfers to a unifi nas Quick notes on swift libraries AI engineering is a different animal San Francisco | Pierce Freeman Debugging a mountaineer rendering segfault Local network config on macOS Building our home network | Pierce Freeman Legacy code and AI copilots Typehinting from day-zero | Pierce Freeman Generating database migrations with acyclic graphs Lofoten | Pierce Freeman Mountaineer v0.1: Webapps in Python and React Constraining LLM Outputs | Pierce Freeman Passthrough above all | Pierce Freeman Accuracy in kudos | Pierce Freeman How quick we are to adapt The curious case of LM repetition Costa Rica | Pierce Freeman Debugging chrome extensions with system-level logging Speeding up runpod | Pierce Freeman Inline footnotes with html templates Parsing Common Crawl in a day for $60 An era of rich CLI All or nothing with remote work The Next 10 Years | Pierce Freeman Adding wheels to flash-attention | Pierce Freeman LLMs as interdisciplinary agents | Pierce Freeman New Zealand | Pierce Freeman Representations in autoregressive models | Pierce Freeman Let's talk about Siri | Pierce Freeman Minimum viable public infrastructure | Pierce Freeman Reasoning vs. Memorization in LLMs Automatically migrate enums in alembic Greater sequence lengths will set us free On learning to ski | Pierce Freeman Dolomites | Pierce Freeman Using grpc with node and typescript Opportunity years | Pierce Freeman Buzzword peaks and valleys | Pierce Freeman Buenos Aires | Pierce Freeman Network routing interaction on MacOS Independent work: November recap | Pierce Freeman Debugging slow pytorch training performance The provenance of copy and paste Debugging tips for neural network training Patagonia | Pierce Freeman Santiago | Pierce Freeman My 2022 digital travel kit AWS vs GCP - GPU Availability V2 Independent work: October recap | Pierce Freeman Planning Patagonia | Pierce Freeman Relationship modeling | Pierce Freeman The power of status updates A new chapter | Pierce Freeman Give my library a coffee shop AWS vs GCP - GPU Availability V1 Switzerland | Pierce Freeman Headfull browsers beat headless | Pierce Freeman Webcrawling tradeoffs | Pierce Freeman Copenhagen | Pierce Freeman
Introducing Envelope.dev | Pierce Freeman
2024-11-12 · via Pierce Freeman

Envelope.dev

I just released Envelope.dev as a private package index for Python libraries. It's a simple way to host your internal packages that doesn't break the bank. It's also the first generally available product built on Mountaineer.

Since the jump we've been building our products at MonkeySee with Python. It lets us move as quickly as we can: our average rate of major feature development is about 6 features per week with just me at the keyboard. We've been able to do this because of the incredible ecosystem of packages available on PyPI. But we've also built out our internal frameworks and libraries to help us move even faster.

Envelope started as an admittedly premature optimization. I looked up after a few months of dev work and realized we had a few codebases that we'd want to reuse across a few different projects: billing, authentication, web parsing, etc. Most were too coupled to the rest of our architecture to be open-sourced. Others covered our core IP. Even though we had no other projects already in the pipeline, it felt like it was worth doing the refactor before we'd need them.

I started as simply as I could: I just refactored the code into separate packages in the same repo. This let us use our existing CI pipelines, since every downstream clone of the repo would also receive the private packages. Doing the install from the main web service could easily be simlinked within our pyproject.toml:

[tool.poetry.dependencies]
mountaineer-billing = { path = "./billing" }
mountaineer-auth = { path = "./auth" }

This worked for as long as we only had one project. But when we needed to start on a second project, we had a heavy lift. Do we want to use a mono-repo for all projects?1 Probably not. So we had to:

  • Refactor the packages to be even more generic. This also required adding tests that could be run in isolation without our web service logic.
  • Place the packages in separate repos.
  • Git clone the package repos and install them in their downstream services everywhere we needed to use them.

This git clone approach worked pretty well. By convention, we cut a new git tag whenever we wanted to release a new version of the package:

[tool.poetry.dependencies]
mountaineer-billing = { git = "https://github.com/piercefreeman/mountaineer_billing.git", branch = "v1.0.0" }
mountaineer-auth = { git = "https://github.com/piercefreeman/mountaineer_auth.git", branch = "v1.0.0" }

This worked for a while until we had to publish wheels. Each wheel needs to be built for multiple architectures: our arm64 laptops, our x86_64 servers, and different versions of Python. CI handles this easily - but where do we store them once they're built? Poetry2 isn't able to dynamically pull wheels from the Assets section of a Github release. If you want this behavior you'll have to install the fully qualified URL of the wheel explicitly on each machine - which changes depending your CPU architecture and Python version.

PEP 503

At the end of the day, what I really needed was just a private PyPI almost at feature parity. Luckily there's a well-documented API for Python package managers specified in PEP 503. Approved back in 2015 it acted as a standardization proposal for how local package managers can fetch remote repository definitions and their included files. Some extensions afterward have clarified how to deal with wheels and other markup to help with performance and local caching. At its simplest, a remote index is just a cascading list of HTML packages that include the a hrefs of different versions to install:

<div>
    <a href="/simple/mountaineer-billing/">
    <a href="/simple/mountaineer-auth/">
</div>
<div>
    <a href="/simple/mountaineer-billing/v1.0.0/">
    <a href="/simple/mountaineer-billing/v1.0.1/">
</div>

The easiest approach seemed to be just generating a static site with the proper HTML structure and hosting it on Github. But the question of how to gate access to the packages remained, since static sites don't support password-protected directories. And the second I was looking at spinning up an additional service to handle this, I realized I was just building a package registry. Might as well do it properly.

Envelope.dev

screenshot

Enter: Envelope.dev. It's a simple package registry to host these internal packages. Following the Linux philosophy, it does one thing and does it well.

The original Envelope was just a static site. We would tag releases as we normally do in Github and have the CI build action upload artifacts to the release. Every 15 minutes a cron job would pull from the release artifacts and build a new password-protected static site with the PEP 503 convention. We would point all our pyproject installers to the static site path.

That initial scope grew to include:

  • Full local caching & remote CDN support
  • Package uploading
  • Customizable access control with keys (limit in time or package version numbers)
  • Full login system

Ironically Envelope become the first service (aside from our primary one) that shared the codebase of internal libraries. So it was the first one that actually would have needed itself.3 Now we have 5 different products including Envelope that all pull from the MonkeySee common code, so it was really worth doing the refactor when we did.

Originally I had intended for it to stay private: easier to manage and less overhead. But it occurred to me that if you were to add billing it's basically a fully built out product. It was easy enough to import that mountaineer-billing component and get off to the races.

WYSIWYG

On the landing page I included a brief note about why I'm doing this. I spent as much time thinking about this as on designing the rest of the landing page:

So here’s my core promise:

  • I’m focusing on Python. There are existing options for other languages.
  • I’m not in this to make money (I do that at my main company). Your subscription here pays for storage and a portion of server costs, that’s it.
  • What you see is what you get. I’m not trying to build 100 new features and charge you for ones you don’t need. Judge us by our current features and not future promises.

Way too much software these days are feature complete and keep getting more bloated. People still just buy them for one or two features. So Envelope from the start is going to stay that way. It's a simple package registry for Python packages. Subscription fees go to paying for storage, CDN, bandwidth, and server costs. That's pretty much it.

It's not going to be a unicorn - it might not even get profitable. But we're using it every day and love it. That remains the software that makes me happiest to use: when someone has clearly solved the problem first for themselves. It's hard to match the labor of love that comes from building something you use every day. You sweat a lot more of the details. If this particular problem reasonates with you, check it out at Envelope.dev.

And if it doesn't resonate - that's cool too. Hopefully you're also building something you love. I hope to see it on the Internet soon.

  1. We certainly could. But I find that most git conventions that work seamlessly in a single repository don't default scale well to a mono-repo. Even tagging a release for deployment brings in the question of whether to deploy all applications or establish some convention for how to limit the ones you want to deploy. Name prefix? Release body text pattern? You have to off-road with more CI when you have more than one application. ↩

  2. Nor any other package manager as far as I know. ↩

  3. There's obviously a chicken and egg problem here. Do we make an MVP service just as long as it takes to host the first artifacts, then upgrade the system using its own prod endpoints?

    This would work in theory but immediately block deployments if prod is down. So instead I went through bootstrapping with a git clone based on a pinned artifact version. It works but very happy I don't have to do this in every project. ↩