洪 民憙 (Hong Minhee) 
@hongminhee@hollo.social · Reply to Jaeyeol Lee's post
@kodingwarrior 제가 Hollo 쪽을 패치해서 Mastodon 흉내 내도록 고쳤어요 ㅋㅋㅋ


@hongminhee@hollo.social · 1038 following · 1608 followers
An intersectionalist, feminist, and socialist living in Seoul (UTC+09:00). @tokolovesme's spouse. Who's behind @fedify, @hollo, and @botkit. Write some free software in #TypeScript, #Haskell, #Rust, & #Python. They/them.
서울에 사는 交叉女性主義者이자 社會主義者. 金剛兔(@tokolovesme)의 配偶者. @fedify, @hollo, @botkit 메인테이너. #TypeScript, #Haskell, #Rust, #Python 等으로 自由 소프트웨어 만듦.
| Website | GitHub | Blog | Hackers' Pub |
|---|---|---|---|

@hongminhee@hollo.social · Reply to Jaeyeol Lee's post
@kodingwarrior 제가 Hollo 쪽을 패치해서 Mastodon 흉내 내도록 고쳤어요 ㅋㅋㅋ

@hongminhee@hollo.social · Reply to kopper :colon_three:'s post
@kopper The composability angle is something I hadn't fully appreciated before—a standalone reply tree indexer that any client can query via proxyUrl is a genuinely interesting pattern, and it's not something you'd get from just standardizing a monolithic client API.
On did:key, you're right that handing over a private key for autonomous server actions is a real problem, and the non-rotatability makes it worse. Though I'd frame that as a limitation of did:key specifically rather than portable identity as a concept—FEP-ef61 mentions other DID methods as candidates, and the broader space of approaches to server-independent identity isn't exhausted by any single proposal.
But agreed that they're orthogonal and can coexist.

@hongminhee@hollo.social · Reply to infinite love ⴳ's post
@trwnh Yes—Fedify is database-agnostic, so tracking which IDs are already in use is the application's responsibility. Fedify handles the federation layer, but the data model and storage are entirely up to the application built on top of it.

@hongminhee@hollo.social · Reply to kopper :colon_three:'s post
@kopper That's a fair point about the Mastodon API—the lexicographic ID requirement and the pagination assumptions are good concrete examples of how standardization quietly closes off design space in ways nobody intended.
I think this exchange has been useful for me in clarifying that we're probably starting from different premises about what C2S is for. If frontend portability isn't the goal, then the case against standardizing the client API makes a lot of sense. I just can't quite let go of the feeling that portability at that layer is what most people imagine when they hear “C2S”—though I'll admit the spec itself is ambiguous enough that neither of us is obviously wrong.
Anyway, thanks for taking the time to respond. Lots to think about.

@hongminhee@hollo.social · Reply to kopper :colon_three:'s post
@kopper Thanks for engaging with this—it helps me think it through more carefully.
Your point about making the split explicit at the protocol level is well taken. I can see how that matters especially for extensions: a lot of FEPs end up adding actor-global state for things that are really client concerns, and having a clearer boundary in the protocol might discourage that drift. That's a concrete benefit I hadn't fully appreciated.
On the interoperability question, I think I see where we differ. You're reframing the core promise of C2S as “reuse the same account across different interfaces,” whereas I'd been reading it as “connect any frontend to any server.” Those lead to quite different designs. I'm not sure which framing is more faithful to what C2S originally intended—maybe neither of us is wrong, and the spec was simply underspecified on this point.
That said, if account portability is the goal, I wonder whether C2S is really the right tool for it. FEP-ef61 and the Nomadic Identity approach both tackle that problem more directly, by making identifiers server-independent at the identity layer rather than standardizing the client–server protocol. It feels like a different layer of the problem altogether, and I'm not sure C2S can carry that weight on its own even with your proposed architecture.
The point about AP objects remaining AP objects through hydration is interesting though. I can see how that keeps the pieces composable even without a standardized client API. I'll have to think about that more.

@hongminhee@hollo.social · Reply to infinite love ⴳ's post
@trwnh Actually, Fedify already supports this quite well. The actor dispatcher gives you full control over the actor's id—you can set it to any URL, including one on a custom domain. And since Fedify 1.4.0, there's a mapAlias() method that lets you handle WebFinger lookups for those custom URLs too. So running Fedify behind a reverse proxy that routes multiple hostnames, and assigning per-actor custom domain identifiers, should be achievable without any changes to Fedify itself.

@hongminhee@hollo.social
Today @kopper shared a post on the fediverse titled how to not regret c2s, and I found it genuinely interesting to read, even if I'm not sure its proposed architecture actually solves what it sets out to solve.
The author's frustration with naïve #C2S implementations is well-founded. Slapping an #ActivityPub facade onto an existing Mastodon-like server and calling it C2S doesn't buy you much—you end up with the rigidity of a bespoke API without any of the interoperability C2S is supposed to offer. The “JSON-LD flavored Mastodon API” framing is apt.
The proposed solution is to split responsibility more aggressively: the C2S server should be nearly stateless and dumb, storing ActivityPub objects without interpreting them, while a separate “client” layer handles indexing, timelines, moderation, and exposes its own API to the frontend running on the user's device. It's a clean separation of concerns on paper.
But here's what bothers me. When you map this architecture onto familiar terms, it looks roughly like this:
That's not a new architecture. That's just the current architecture with the labels shifted. The interesting question is which interface gets standardized, and the author's answer is the one between the C2S server and the “client” layer—the bottom boundary.
The problem is that what people actually want from C2S is to connect any frontend to any server. The portability they're after lives at the top boundary, between the frontend and whatever is behind it. But the author explicitly argues against standardizing that layer: “we don't really need a standardized api,” they write, leaving each client free to expose whatever API it likes.
Which means frontends remain locked to specific clients, just as Mastodon apps are locked to the Mastodon API today. The interoperability promise of C2S—log in to any server with any app—isn't actually delivered. It's been pushed one layer down, out of reach of the end user.
There's real value in the post's thinking about data hosting vs. interpretation, and about the security implications of servers that understand too much. But as an answer to the question C2S is supposed to answer, I'm not convinced.

@kopper@not-brain.d.on-t.work

@hongminhee@hollo.social · Reply to infinite love ⴳ's post
@trwnh Fedify does run well behind a reverse proxy, and it doesn't actually require a fixed base URL—it can derive the base URL from the incoming request. Ghost takes advantage of exactly this to implement virtual hosting on top of Fedify, so in principle the kind of per-actor custom domain you're describing should already be achievable without changes to Fedify itself.

@hongminhee@hollo.social · Reply to infinite love ⴳ's post
@trwnh Fedify currently doesn't support binding a custom domain to individual actors—all actors share the server's domain. Honestly, I'm not sure how that would work in practice either; it would need some kind of indirection or delegation mechanism at the HTTP level, and I'm not aware of an established spec for it. Do you have something specific in mind, or perhaps an approach you've been thinking about?

@hongminhee@hollo.social · Reply to Marcus Rohrmoser 🌻's post
@mro That's a fair point about design by committee, and I don't disagree that RFC 9421 added complexity without proportionate benefit. But I think it's a somewhat separate question from what I was getting at.
Even if every ActivityPub spec had been designed with ruthless simplicity—no committee sprawl, no redundant signature schemes—the DX problem would still be there. You'd still need to know what to do when a property arrives as a string instead of an array. You'd still need to handle embedded objects vs. URIs. The gap between “I understand ActivityPub conceptually” and “I can ship something that actually federates correctly” would still be wide.
My point isn't really about why the stack is complex. It's that the complexity, whatever its origin, currently falls entirely on the application developer. A framework should be able to absorb most of that—the same way web frameworks absorbed HTTP parsing and content negotiation—so developers can focus on what their app actually does.
(And yes, the CGI analogy was never meant to be architectural criticism! Just reaching for a feeling most of us remember.)
@obsidian@mas.to
Obsidian Sync now has a headless client, so you can sync vaults to a server without using the desktop app.
Try the open beta:
@rick@rmendes.net · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post

@hongminhee@hollo.social · Reply to Ricardo's post
@rick Great work, Ricardo! And thank you for using Fedify!

@hongminhee@hollo.social · Reply to silverpill's post
@silverpill That's right. I think client-side abstraction will be necessary when ActivityPub C2S interactions become more widespread, too.
@julian@activitypub.space · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post
@hongminhee@hollo.social I think you're completely right, and this is coming from somebody who went deep into the weeds of ActivityPub when building out his own implementation.
Generic C2S servers offload the server side aspects to a trusted third party.
Generic S2S frameworks (like fedify!) give you even more control.
We need both! We need fewer idiots like me who decided to implement the entire protocol from the ground up 🤣
Do it @hongminhee@hollo.social! DEPRECATE ALL MY HARD WORK ALREADY!!!
@silverpill@mitra.social · Reply to 洪 民憙 (Hong Minhee) :nonbinary:'s post
@hongminhee Better developer tooling is the only correct answer to rising complexity. Getting 200 different servers to smoothly interoperate is impossible, but we can do that with 10 libraries.

@hongminhee@hollo.social · Reply to julian's post
@julian Haha, most ActivityPub implementers have their own frameworks, they just haven't separated them out! It would be really great if there were full-featured ActivityPub frameworks for each of the major programming languages.

@hongminhee@hollo.social
When I first started working with #ActivityPub, before #Fedify existed, it felt like writing web apps in Perl and CGI in the late '90s. Interesting, even exciting—but never comfortable. That era where your business logic and your protocol plumbing were just… the same thing:
print "HTTP/1.1 200 OK"
print "Content-Type: text/html"
print
print "Hello, world!"Decades of web development have given us layers of abstraction we now take for granted. Nobody hand-parses application/x-www-form-urlencoded query strings anymore. Nobody writes their own JSON codec, or manually constructs HTTP request/response messages. These things just aren't your problem when you're building an app.
ActivityPub development still feels like they are your problem. What do you do when the https://www.w3.org/ns/activitystreams#actor property comes in as a string instead of an array? What about when https://www.w3.org/ns/activitystreams#object is an embedded entity rather than a URI? How exactly do you implement HTTP Signatures? And wait—what's Linked Data Signatures, and do you need that too?
The real issue isn't that ActivityPub is complicated per se. It's that you can't get away with understanding it at a high level. You have to know it the way an implementor knows it—every edge case, every inconsistency in how different servers serialize JSON-LD, every signature scheme that exists in the wild. That's a lot to learn before you can even start thinking about your actual app. And when developers understandably cut corners on the protocol to focus on their product, it quietly becomes an interoperability problem for the whole ecosystem.
What I want ActivityPub development to feel like: you spend a day understanding the big picture, and then you just… build your app. That was the goal when I started Fedify, and honestly, we're not fully there yet. But it's where I want to get.
@erlend_sh@socialhub.activitypub.rocks
Fedify has just laid out a comprehensive implementation plan for this fep:
https://github.com/fedify-dev/fedify/issues/288#issuecomment-3971459585
The core idea is replacing HTTP(S) URIs with server-independent identifiers:
ap://URIs that use a Decentralized Identifier (DID) as the authority component, rather than a domain name. An object identified asap://did:key:z6Mk…/actorcan live on multiple servers simultaneously and survives any single server disappearing.

@hongminhee@hollo.social · Reply to Jupiter Rowland's post
@jupiter_rowland Full nomadic identity—the kind Forte and (Streams) have—is something I'd like to support in Fedify eventually. But for now, I'm focusing on the more modest goal: server-independent object identifiers that survive a server disappearing. The multi-server synchronization side of things feels premature to build out seriously until the relevant specs (FEP-ef61 itself is still DRAFT, after all) stabilize a bit more. Once the standardization catches up, I'd like to revisit.
Thanks for the context on @mikedev and the history here—I wasn't fully aware of how deep the roots of nomadic identity go.

@hongminhee@hollo.social · Reply to 志文's post
@shimon1024 おお…すごいですね!素晴らしいです!ぜひお会いしていろいろと学ばせていただきたいです。
ところで、今回の東京行きにご一緒するHaze Leeさん(@nebuleto)も同席してもよろしいでしょうか?(日本語は話せます)

@hongminhee@hollo.social · Reply to 志文's post
@shimon1024 おお、モンゴル文字対応ですか…興味深いですね!モンゴル文字については浅学ですが、もっと深くお話ししたいです。私は自作のActivityPub実装であるHolloに、漢字混じりの韓国語(所謂「国漢文混用体」)に振りハングル(振り仮名のハングル版)を付ける機能を実装したことがあります。もしよろしければ、DMで具体的なお約束を決めませんか?

@hongminhee@hollo.social · Reply to silverpill's post
@silverpill Thanks for the clarification! I think I was overcomplicating it—I was imagining a scenario where gateway A forwards a received activity to gateway B, and wondering how B could trust that A hadn't tampered with it. But of course, since portable activities must carry FEP-8b32 integrity proofs, the authenticity of the activity itself can always be verified regardless of which server forwarded it. No separate gateway-to-gateway authentication mechanism is needed.
And the gateways-based trust makes sense now as a mechanism specifically for unauthenticated collections—if a collection comes from a server listed in the actor's gateways array, proof verification can be skipped; otherwise it's required.
@fedify@hollo.social
Jiwon (@z9mb1), one of our core contributors, drew a Fedify dino! How cute!
https://oeee.cafe/@z9mb1/2b5b0baf-466b-4c65-a1e0-d3588f0666f4
@z9mb1@oeee.cafe
Fedify dino for notice
https://kre.pe/CKwN This is a paid request :) fediverse logo was attached afterwards.
@z9mb1@oeee.cafe
Fedify dino for notice
https://kre.pe/CKwN This is a paid request :) fediverse logo was attached afterwards.

@hongminhee@hollo.social
Started laying out a rough plan for implementing FEP-ef61: Portable Objects in #Fedify—server-independent #ActivityPub identities backed by #DIDs, multi-server replication, and client-side signing. It's going to be a long road (13 tasks across 5 phases, with a few open questions that need answering before we even begin), but I think it's worth doing right.
https://github.com/fedify-dev/fedify/issues/288#issuecomment-3971459585
@mapache@hachyderm.io
I have so much fun tin the fediverse, this is a very cozy place.

@hongminhee@hollo.social · Reply to hyunjoon's post
@hyunjoon 그냥 字體가 다른 건데… 어느 쪽이 좀 더 《康熙字典》 字體에 가깝냐를 基準으로 쓰고 있습니다. ㅎㅎㅎ

@hongminhee@hollo.social
國漢文으로 韓國語 쓸 때 「産」 代身 「產」을 쓰는 便. 비슷하게 「畵」 代身 「畫」를 쓴다거나, 「査」 代身 「查」를 쓴다거나 하는 게 있음. 아무도 神經 안 쓰겠지만… ㅋㅋㅋ

@hongminhee@hollo.social
슬슬 Fedify 스티커도 좀 더 生產해야…