洪 民憙 (Hong Minhee) :nonbinary:'s avatar

洪 民憙 (Hong Minhee) :nonbinary:

@hongminhee@hollo.social

1,118 following1,657 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 , , , & . They/them.

서울에 사는 交叉女性主義者이자 社會主義者. 金剛兔(@tokolovesme)의 配偶者. @fedify, @hollo, @botkit 메인테이너. , , , 等으로 自由 소프트웨어 만듦.

()

Pinned

@hongminhee@hollo.social

Hello! I'm Hong Minhee (洪 民憙), an open source software engineer in my late 30s, living in Seoul, Korea. I'm bisexual and non-binary (they/them), and an enthusiastic advocate of free/open source software and the fediverse.

I work full-time on @fedify, an ActivityPub server framework in TypeScript, funded by @sovtechfund. I'm also the creator of @hollo, a single-user ActivityPub microblog; @botkit, an ActivityPub bot framework; Hackers' Pub, a fediverse platform for software developers; and LogTape, a logging library for JavaScript and TypeScript.

I have a long interest in East Asian languages (CJK) and Unicode. I post mostly in English here, though occasionally in Japanese or in mixed-script Korean (國漢文混用體), a traditional writing style that interleaves Chinese characters with the native Korean alphabet. Wanting to write in that style was actually one of the reasons I joined the fediverse. Feel free to talk to me in English, Korean, Japanese, or even Literary Chinese!

en.wikipedia.org

Korean mixed script - Wikipedia

Pinned

はじめまして!ソウル在住の30代後半のオープンソースソフトウェアエンジニア、洪 民憙(ホン・ミンヒ)と申します。バイセクシュアル(bisexual)・ノンバイナリー(non-binary)で、自由・オープンソースソフトウェア(F/OSS)とフェディバース(fediverse)の熱烈な支持者です。

STF(@sovtechfund)の支援を受け、TypeScript用ActivityPubサーバーフレームワーク「@fedify」の開発に専念しています。他にも、おひとり様向けのActivityPubマイクロブログ「@hollo」、ActivityPubボットフレームワーク「@botkit」、ソフトウェア開発者向けフェディバースプラットフォームHackers' Pub、JavaScript・TypeScript用ロギングライブラリLogTapeなどの制作者でもあります。

東アジア言語(いわゆるCJK)とUnicodeにも興味があります。このアカウントでは主に英語で投稿していますが、時々日本語や国漢文混用体(漢字ハングル混じり文)の韓国語でも書いています。実はこの文体で書きたくてフェディバースを始めた、という経緯もあります。日本語、英語、韓国語、漢文でも気軽に話しかけてください!

speakerdeck.com

国漢文混用体からHolloまで

本発表では、韓国語の「国漢文混用体」(漢字ハングル混じり文)を自分のフェディバース投稿に実装したいという小さな目標から始まった旅路を共有します。 この目標を達成するために、ActivityPubのJSON-LDの複雑さやHTTP Signatures、WebFingerなどの仕様を理解する必要性に…

Pinned

安寧(안녕)하세요! 저는 서울에 살고 있는 30代(대) 後半(후반)의 오픈 소스 소프트웨어 엔지니어 洪民憙(홍민희)입니다. 兩性愛者(양성애자)(bisexual)이자 논바이너리(non-binary)이며, 自由(자유)·오픈 소스 소프트웨어(F/OSS)와 聯合宇宙(연합우주)(fediverse)의 熱烈(열렬)한 支持者(지지자)이기도 합니다.

STF(@sovtechfund)의 支援(지원)을 받아 TypeScript用(용) ActivityPub 서버 프레임워크 @fedify 開發(개발)에 專業(전업)으로 任(임)하고 있습니다. 그 外(외)에도 싱글 유저用(용) ActivityPub 마이크로블로그 @hollo, ActivityPub 봇 프레임워크 @botkit, 소프트웨어 開發者(개발자)를 위한 聯合宇宙(연합우주) 플랫폼 Hackers' Pub, JavaScript·TypeScript用(용) 로깅 라이브러리 LogTape 等(등)의 製作者(제작자)이기도 합니다.

東(동)아시아 言語(언어)(이른바 CJK)와 Unicode에도 關心(관심)이 많습니다. 이 計定(계정)에서는 主(주)로 英語(영어)로 포스팅하지만, 때때로 日本語(일본어)나 國漢文混用體(국한문 혼용체) 韓國語(한국어)로도 씁니다. 聯合宇宙(연합우주)에 오게 된 動機(동기) 中(중) 하나가 바로 國漢文混用體(국한문 혼용체)로 글을 쓰고 싶었기 때문이기도 하고요. 韓國語(한국어), 英語(영어), 日本語(일본어), 아니면 漢文(한문)으로도 말을 걸어주세요!

logtape.org

LogTape

Unobtrusive logging library with zero dependencies—library-first design for Deno, Node.js, Bun, browsers, and edge functions

@tesaguri@fedibird.com

ActivityPubの仕様の策定、RDFトリビアの議論で無限に時間を食っている感はある

@2chanhaeng@hackers.pub · Reply to Jaeyeol Lee

@kodingwarrior 요런 디자인은 어떠세용

Hackers' public
1st MEETUP @SEOUL

2025. 09. 14. 15:00 KST
서울특별시 성동구 상원길 26 튜링의 사과

Code As A Canvas : 코드에서 예술작품이 되기까지 (@jakeseo@hackers.pub)

폰트는 어떻게 만들어지는가 - NeoDGM 사례로 살펴보는 개발 후일담 (@dalgona@hackers.pub)
ALT text

Hackers' public 1st MEETUP @SEOUL 2025. 09. 14. 15:00 KST 서울특별시 성동구 상원길 26 튜링의 사과 Code As A Canvas : 코드에서 예술작품이 되기까지 (@jakeseo@hackers.pub) 폰트는 어떻게 만들어지는가 - NeoDGM 사례로 살펴보는 개발 후일담 (@dalgona@hackers.pub)

@cheeaun@mastodon.social

This has been in the to-do list for years.

Yes, custom emojis work inside CW and poll fields :blobpeek:

Demo of inserting custom emojis inside content warning fields and poll fields in the composer on Phanpy.
ALT text

Demo of inserting custom emojis inside content warning fields and poll fields in the composer on Phanpy.

@hongminhee@hollo.social

0.3.0 is out with dependent options and flexible parser composition, shaped by feedback from @z9mb1's work migrating @fedify CLI from Cliffy to Optique.

https://hackers.pub/@hongminhee/2025/optique-030

hackers.pub

Optique 0.3.0: Dependent options and flexible composition

Optique 0.3.0 introduces several enhancements aimed at simplifying the development of complex CLI applications. This release focuses on expanding parser flexibility and refining the help system, incorporating valuable community feedback. Key updates include the introduction of required Boolean flags using the new `flag()` parser, more flexible type defaults in `withDefault()` to support union types, and an extended `or()` capacity that now supports up to 10 parsers. The `merge()` combinator has also been enhanced to work with any object-producing parser, and context-aware help is now available through the `longestMatch()` combinator. Additionally, version display support has been added to both `@optique/core` and `@optique/run`, along with structured output functions for consistent terminal formatting. These improvements collectively provide developers with more powerful tools for building intuitive and feature-rich command-line interfaces.

@hongminhee@hackers.pub

We're releasing Optique 0.3.0 with several improvements that make building complex CLI applications more straightforward. This release focuses on expanding parser flexibility and improving the help system based on feedback from the community, particularly from the Fedify project's migration from Cliffy to Optique. Special thanks to @z9mb1 for her invaluable insights during this process.

What's new

  • Required Boolean flags with the new flag() parser for dependent options patterns
  • Flexible type defaults in withDefault() supporting union types for conditional CLI structures
  • Extended or() capacity now supporting up to 10 parsers (previously 5)
  • Enhanced merge() combinator that works with any object-producing parser, not just object()
  • Context-aware help using the new longestMatch() combinator
  • Version display support in both @optique/core and @optique/run
  • Structured output functions for consistent terminal formatting

Required Boolean flags with flag()

The new flag() parser creates Boolean flags that must be explicitly provided. While option() defaults to false when absent, flag() fails parsing entirely if not present. This subtle difference enables cleaner patterns for dependent options.

Consider a scenario where certain options only make sense when a mode is explicitly enabled:

import { flag, object, option, withDefault } from "@optique/core/parser";
import { integer } from "@optique/core/valueparser";

// Without the --advanced flag, these options aren't available
const parser = withDefault(
  object({
    advanced: flag("--advanced"),
    maxThreads: option("--threads", integer()),
    cacheSize: option("--cache-size", integer())
  }),
  { advanced: false as const }
);

// Usage:
// myapp                    → { advanced: false }
// myapp --advanced         → Error: --threads and --cache-size required
// myapp --advanced --threads 4 --cache-size 100 → Success

This pattern is particularly useful for confirmation flags (--yes-i-am-sure) or mode switches that fundamentally change how your CLI behaves.

Union types in withDefault()

Previously, withDefault() required the default value to match the parser's type exactly. Now it supports different types, creating union types that enable conditional CLI structures:

const conditionalParser = withDefault(
  object({
    server: flag("-s", "--server"),
    port: option("-p", "--port", integer()),
    host: option("-h", "--host", string())
  }),
  { server: false as const }
);

// Result type is now a union:
// | { server: false }
// | { server: true, port: number, host: string }

This change makes it much easier to build CLIs where different flags enable different sets of options, without resorting to complex or() chains.

More flexible merge() combinator

The merge() combinator now accepts any parser that produces object-like values. Previously limited to object() parsers, it now works with withDefault(), map(), and other transformative parsers:

const transformedConfig = map(
  object({
    host: option("--host", string()),
    port: option("--port", integer())
  }),
  ({ host, port }) => ({ endpoint: `${host}:${port}` })
);

const conditionalFeatures = withDefault(
  object({
    experimental: flag("--experimental"),
    debugLevel: option("--debug-level", integer())
  }),
  { experimental: false as const }
);

// Can now merge different parser types
const appConfig = merge(
  transformedConfig,        // map() result
  conditionalFeatures,      // withDefault() parser
  object({                  // traditional object()
    verbose: option("-v", "--verbose")
  })
);

This improvement came from recognizing that many parsers ultimately produce objects, and artificially restricting merge() to only object() parsers was limiting composition patterns.

Context-aware help with longestMatch()

The new longestMatch() combinator selects the parser that consumes the most input tokens. This enables sophisticated help systems where command --help shows help for that specific command rather than global help:

const normalParser = object({
  help: constant(false),
  command: or(
    command("list", listOptions),
    command("add", addOptions)
  )
});

const contextualHelp = object({
  help: constant(true),
  commands: multiple(argument(string())),
  helpFlag: flag("--help")
});

const cli = longestMatch(normalParser, contextualHelp);

// myapp --help           → Shows global help
// myapp list --help      → Shows help for 'list' command
// myapp add --help       → Shows help for 'add' command

The run() functions in both @optique/core/facade and @optique/run now use this pattern automatically, so your CLI gets context-aware help without any additional configuration.

Version display support

Both @optique/core/facade and @optique/run now support version display through --version flags and version commands. See the runners documentation for details:

// @optique/run - simple API
run(parser, {
  version: "1.0.0",  // Adds --version flag
  help: "both"
});

// @optique/core/facade - detailed control
run(parser, "myapp", args, {
  version: {
    mode: "both",     // --version flag AND version command
    value: "1.0.0",
    onShow: process.exit
  }
});

The API follows the same pattern as help configuration, keeping things consistent and predictable.

Structured output functions

The new output functions in @optique/run provide consistent terminal formatting with automatic capability detection. Learn more in the messages documentation:

import { print, printError, createPrinter } from "@optique/run";
import { message } from "@optique/core/message";

// Standard output with automatic formatting
print(message`Processing ${filename}...`);

// Error output to stderr with optional exit
printError(message`File ${filename} not found`, { exitCode: 1 });

// Custom printer for specific needs
const debugPrint = createPrinter({
  stream: "stderr",
  colors: true,
  maxWidth: 80
});

debugPrint(message`Debug: ${details}`);

These functions automatically detect terminal capabilities and apply appropriate formatting, making your CLI output consistent across different environments.

Breaking changes

While we've tried to maintain backward compatibility, there are a few changes to be aware of:

  • The help option in @optique/run no longer accepts "none". Simply omit the option to disable help.
  • Custom parsers implementing getDocFragments() need to update their signature to use DocState<TState> instead of direct state values.
  • The object() parser now uses greedy parsing, attempting to consume all matching fields in one pass. This shouldn't affect most use cases but may change parsing order in complex scenarios.

Upgrading to 0.3.0

To upgrade to Optique 0.3.0, update both packages:

# Deno (JSR)
deno add @optique/core@^0.3.0 @optique/run@^0.3.0

# npm
npm update @optique/core @optique/run

# pnpm
pnpm update @optique/core @optique/run

# Yarn
yarn upgrade @optique/core @optique/run

# Bun
bun update @optique/core @optique/run

If you're only using the core package:

# Deno (JSR)
deno add @optique/core@^0.3.0

# npm
npm update @optique/core

Looking ahead

These improvements came from real-world usage and community feedback. We're particularly interested in hearing how the new dependent options patterns work for your use cases, and whether the context-aware help system meets your needs.

As always, you can find complete documentation at optique.dev and file issues or suggestions on GitHub.

github.com

GitHub - dahlia/optique: Type-safe combinatorial CLI parser for TypeScript

Type-safe combinatorial CLI parser for TypeScript. Contribute to dahlia/optique development by creating an account on GitHub.

@hongminhee@hollo.social

0.3.0 is out with dependent options and flexible parser composition, shaped by feedback from @z9mb1's work migrating @fedify CLI from Cliffy to Optique.

https://hackers.pub/@hongminhee/2025/optique-030

hackers.pub

Optique 0.3.0: Dependent options and flexible composition

Optique 0.3.0 introduces several enhancements aimed at simplifying the development of complex CLI applications. This release focuses on expanding parser flexibility and refining the help system, incorporating valuable community feedback. Key updates include the introduction of required Boolean flags using the new `flag()` parser, more flexible type defaults in `withDefault()` to support union types, and an extended `or()` capacity that now supports up to 10 parsers. The `merge()` combinator has also been enhanced to work with any object-producing parser, and context-aware help is now available through the `longestMatch()` combinator. Additionally, version display support has been added to both `@optique/core` and `@optique/run`, along with structured output functions for consistent terminal formatting. These improvements collectively provide developers with more powerful tools for building intuitive and feature-rich command-line interfaces.

@hongminhee@hackers.pub

We're releasing Optique 0.3.0 with several improvements that make building complex CLI applications more straightforward. This release focuses on expanding parser flexibility and improving the help system based on feedback from the community, particularly from the Fedify project's migration from Cliffy to Optique. Special thanks to @z9mb1 for her invaluable insights during this process.

What's new

  • Required Boolean flags with the new flag() parser for dependent options patterns
  • Flexible type defaults in withDefault() supporting union types for conditional CLI structures
  • Extended or() capacity now supporting up to 10 parsers (previously 5)
  • Enhanced merge() combinator that works with any object-producing parser, not just object()
  • Context-aware help using the new longestMatch() combinator
  • Version display support in both @optique/core and @optique/run
  • Structured output functions for consistent terminal formatting

Required Boolean flags with flag()

The new flag() parser creates Boolean flags that must be explicitly provided. While option() defaults to false when absent, flag() fails parsing entirely if not present. This subtle difference enables cleaner patterns for dependent options.

Consider a scenario where certain options only make sense when a mode is explicitly enabled:

import { flag, object, option, withDefault } from "@optique/core/parser";
import { integer } from "@optique/core/valueparser";

// Without the --advanced flag, these options aren't available
const parser = withDefault(
  object({
    advanced: flag("--advanced"),
    maxThreads: option("--threads", integer()),
    cacheSize: option("--cache-size", integer())
  }),
  { advanced: false as const }
);

// Usage:
// myapp                    → { advanced: false }
// myapp --advanced         → Error: --threads and --cache-size required
// myapp --advanced --threads 4 --cache-size 100 → Success

This pattern is particularly useful for confirmation flags (--yes-i-am-sure) or mode switches that fundamentally change how your CLI behaves.

Union types in withDefault()

Previously, withDefault() required the default value to match the parser's type exactly. Now it supports different types, creating union types that enable conditional CLI structures:

const conditionalParser = withDefault(
  object({
    server: flag("-s", "--server"),
    port: option("-p", "--port", integer()),
    host: option("-h", "--host", string())
  }),
  { server: false as const }
);

// Result type is now a union:
// | { server: false }
// | { server: true, port: number, host: string }

This change makes it much easier to build CLIs where different flags enable different sets of options, without resorting to complex or() chains.

More flexible merge() combinator

The merge() combinator now accepts any parser that produces object-like values. Previously limited to object() parsers, it now works with withDefault(), map(), and other transformative parsers:

const transformedConfig = map(
  object({
    host: option("--host", string()),
    port: option("--port", integer())
  }),
  ({ host, port }) => ({ endpoint: `${host}:${port}` })
);

const conditionalFeatures = withDefault(
  object({
    experimental: flag("--experimental"),
    debugLevel: option("--debug-level", integer())
  }),
  { experimental: false as const }
);

// Can now merge different parser types
const appConfig = merge(
  transformedConfig,        // map() result
  conditionalFeatures,      // withDefault() parser
  object({                  // traditional object()
    verbose: option("-v", "--verbose")
  })
);

This improvement came from recognizing that many parsers ultimately produce objects, and artificially restricting merge() to only object() parsers was limiting composition patterns.

Context-aware help with longestMatch()

The new longestMatch() combinator selects the parser that consumes the most input tokens. This enables sophisticated help systems where command --help shows help for that specific command rather than global help:

const normalParser = object({
  help: constant(false),
  command: or(
    command("list", listOptions),
    command("add", addOptions)
  )
});

const contextualHelp = object({
  help: constant(true),
  commands: multiple(argument(string())),
  helpFlag: flag("--help")
});

const cli = longestMatch(normalParser, contextualHelp);

// myapp --help           → Shows global help
// myapp list --help      → Shows help for 'list' command
// myapp add --help       → Shows help for 'add' command

The run() functions in both @optique/core/facade and @optique/run now use this pattern automatically, so your CLI gets context-aware help without any additional configuration.

Version display support

Both @optique/core/facade and @optique/run now support version display through --version flags and version commands. See the runners documentation for details:

// @optique/run - simple API
run(parser, {
  version: "1.0.0",  // Adds --version flag
  help: "both"
});

// @optique/core/facade - detailed control
run(parser, "myapp", args, {
  version: {
    mode: "both",     // --version flag AND version command
    value: "1.0.0",
    onShow: process.exit
  }
});

The API follows the same pattern as help configuration, keeping things consistent and predictable.

Structured output functions

The new output functions in @optique/run provide consistent terminal formatting with automatic capability detection. Learn more in the messages documentation:

import { print, printError, createPrinter } from "@optique/run";
import { message } from "@optique/core/message";

// Standard output with automatic formatting
print(message`Processing ${filename}...`);

// Error output to stderr with optional exit
printError(message`File ${filename} not found`, { exitCode: 1 });

// Custom printer for specific needs
const debugPrint = createPrinter({
  stream: "stderr",
  colors: true,
  maxWidth: 80
});

debugPrint(message`Debug: ${details}`);

These functions automatically detect terminal capabilities and apply appropriate formatting, making your CLI output consistent across different environments.

Breaking changes

While we've tried to maintain backward compatibility, there are a few changes to be aware of:

  • The help option in @optique/run no longer accepts "none". Simply omit the option to disable help.
  • Custom parsers implementing getDocFragments() need to update their signature to use DocState<TState> instead of direct state values.
  • The object() parser now uses greedy parsing, attempting to consume all matching fields in one pass. This shouldn't affect most use cases but may change parsing order in complex scenarios.

Upgrading to 0.3.0

To upgrade to Optique 0.3.0, update both packages:

# Deno (JSR)
deno add @optique/core@^0.3.0 @optique/run@^0.3.0

# npm
npm update @optique/core @optique/run

# pnpm
pnpm update @optique/core @optique/run

# Yarn
yarn upgrade @optique/core @optique/run

# Bun
bun update @optique/core @optique/run

If you're only using the core package:

# Deno (JSR)
deno add @optique/core@^0.3.0

# npm
npm update @optique/core

Looking ahead

These improvements came from real-world usage and community feedback. We're particularly interested in hearing how the new dependent options patterns work for your use cases, and whether the context-aware help system meets your needs.

As always, you can find complete documentation at optique.dev and file issues or suggestions on GitHub.

github.com

GitHub - dahlia/optique: Type-safe combinatorial CLI parser for TypeScript

Type-safe combinatorial CLI parser for TypeScript. Contribute to dahlia/optique development by creating an account on GitHub.

@hongminhee@hollo.social

Recently, whenever I write or share (boost) a post on my hollo.social instance, the server consistently crashes immediately afterward, and I haven't found the cause yet. Since I haven't received similar reports from other Hollo users, I suspect it might be an issue with my deployment configuration…

@kodingwarrior@hackers.pub

Hi there 👋

I’m Jaeyeol, a software engineer who loves Neovim and Zed. I see myself as a pragmatic builder — I focus on creating software that I’d genuinely want to use, made for people rather than for technology’s sake. Beyond coding, I also experiment actively within developer communities, often initiating gatherings and exploring new ways for people to connect and share.

One of my current personal projects happens to be in the fediverse space: cosmoslide — a slideshare-like service for sharing presentations across the fediverse. It’s built with NestJS (@fedify/nestjs) for the backend, Next.js for the frontend (most of it is vibe-coded, so I’ll probably rewrite it later 😅)

The project is still in development, with an expected first release between late September and mid October. It started as a personal experiment, but I’m excited to see how it may contribute to the broader fediverse ecosystem.

I enjoy meeting others who are curious about new ideas, whether in technology or in community.

github.com

GitHub - cosmoslide/cosmoslide

Contribute to cosmoslide/cosmoslide development by creating an account on GitHub.

@botkit@hollo.social

We're excited to announce the release of BotKit 0.3.0! This release marks a significant milestone as now supports .js alongside , making it accessible to a wider audience. The minimum required Node.js version is 22.0.0. This dual-runtime support means you can now choose your preferred runtime while building with the same powerful BotKit APIs.

One of the most requested features has landed: poll support! You can now create interactive polls in your messages, allowing followers to vote on questions with single or multiple-choice options. Polls are represented as ActivityPub Question objects with proper expiration times, and your bot can react to votes through the new onVote event handler. This feature enhances engagement possibilities and brings BotKit to feature parity with major platforms like Mastodon and Misskey.

// Create a poll with multiple choices
await session.publish(text`What's your favorite programming language?`, {
  class: Question,
  poll: {
    multiple: true,  // Allow multiple selections
    options: ["JavaScript", "TypeScript", "Python", "Rust"],
    endTime: Temporal.Now.instant().add({ hours: 24 }),
  },
});

// Handle votes
bot.onVote = async (session, vote) => {
  console.log(`${vote.actor} voted for "${vote.option}"`);
};

The web frontend has been enhanced with a new followers page, thanks to the contribution from Hyeonseo Kim (@gaebalgom)! The /followers route now displays a paginated list of your bot's followers, and the follower count on the main profile page is now clickable, providing better visibility into your bot's audience. This improvement makes the web interface more complete and user-friendly.

For developers looking for alternative storage backends, we've introduced the SqliteRepository through the new @fedify/botkit-sqlite package. This provides a production-ready SQLite-based storage solution with ACID compliance, write-ahead logging (WAL) for optimal performance, and proper indexing. Additionally, the new @fedify/botkit/repository module offers MemoryCachedRepository for adding an in-memory cache layer on top of any repository implementation, improving read performance for frequently accessed data.

This release also includes an important security update: we've upgraded to 1.8.8, ensuring your bots stay secure and compatible with the latest ActivityPub standards. The repository pattern has been expanded with new interfaces and types like RepositoryGetMessagesOptions, RepositoryGetFollowersOptions, and proper support for polls storage through the KvStoreRepositoryPrefixes.polls option, providing more flexibility for custom implementations.

botkit.fedify.dev

Repository | BotKit by Fedify

A repository is a data access object that provides an abstraction over the underlying data source. This document provides an overview of repositories and how they are used in the framework.

@mck@hackers.pub

직원용 ETL CLI 인터페이스를 대충 해뒀는데 조만간 optique로 정리해야겠다

@TuringAppleDev@mastodon.social

안녕하세요. 성수동에 위치한 개발자 아지트 공간 튜링의사과입니다.

Mastodon 이전에 가입 후 관리를 못했지만 앞으로는 꾸준한 활동으로 인사 드리겠습니다. 잘 부탁드립니다. 😀

@hongminhee@hackers.pub
@silverpill@mitra.social · Reply to Emelia 👸🏻

@thisismissem

>moving on AT Proto is much simpler for users than moving on ActivityPub, where you don't get to keep your posts currently

Can keep the posts too if your server implements FEP-ef61.

>So if the government decides to crack down on your fediverse instance, you're more screwed than if they crack down on Bluesky PBC or bluesky.social

In the worst case you just sign up on another Fediverse instance. The rest of the network is still there and all connections can be restored.

If Bluesky shuts down, it's over. They control almost all infrastructure. They control did:plc which is centralized. They have developers, moderators, and they have funding. Once all of that disappears, only a tiny group of power users remains who will burn out in a month.

@stinerman @Gargron @tom

codeberg.org

fep/fep/ef61/fep-ef61.md at main

fep - Fediverse Enhancement Proposals

@silverpill@mitra.social
@fediversereport@mastodon.social
@julian@community.nodebb.org · Reply to Connected Places

The issue of SocialHub is an interesting one, because where we are today is an odd situation where you have activitypub developers fragmented across multiple collaborative channels.

  • Some discuss their issues on their respective repositories only
  • Some discuss on SocialHub
  • Some discuss on Matrix channels

However, the bottom line truth is as follows: every ActivityPub developer is on the fediverse, ergo why shouldn't ActivityPub-focused discussions take place on the fediverse as well?

Up until this year, SocialHub has been an island separate from the fediverse. I used this analogy in my talk at fedicon to describe how lonely starting a community can be.

To SocialHub's credit, they have created a community of ActivityPub developers that exists to this day, kudos to them! The question remains now whether SocialHub performing their function adequately — to bring together ActivityPub developers of all stripes.

That's a question worth exploring in and of itself.

cc @fediversereport@mastodon.social @julian@activitypub.space

activitypub.space

julian

@cheeaun@mastodon.social

🤔 Looking at this UI, Forem could probably implement ActivityPub at this point.

Every logo is a server. "Forem feed" = Federated timeline. "Follow" = follow and adding their Local timeline to my Following timeline? 🤔

Related discussion: github.com/forem/forem/discuss (Aug 2018)

Forem's site with logos on the left side of the page. Hovering over every logo shows a popover with more info about its "subforem" and a "Follow" button.
ALT text

Forem's site with logos on the left side of the page. Hovering over every logo shows a popover with more info about its "subforem" and a "Follow" button.

@kodingwarrior@hackers.pub

Hackers' Public @ Seoul 1회차 모임 (1차 모집)

서울에서 열리는 Hackers' Pub 오프라인 밋업, "Hackers' Public @ Seoul"이 2025월 9월 14일(일) 처음으로 개최됩니다. 처음 열리는 밋업인 만큼, 참여하는 많은 분들이 재밌게 느낄 수 있는 소재 위주로 연사자 분들을 섭외했습니다.

  • 일시 : 9월 14일 (일) 오후 3시 ~ 오후 6시
  • 장소 : 서울특별시 성동구 상원길 26, 튜링의사과
  • 주제
    • Code As A Canvas : 코드에서 예술작품이 되기까지 (@jakeseo)
    • 폰트는 어떻게 만들어지는가 - NeoDGM 사례로 살펴보는 개발 후일담 (@dalgona)

강연이 끝나고 난 뒤에 자유롭게 네트워킹하는 시간을 가질 예정입니다. 각자 얘기하고 싶은 주제를 들고 오시면 좋습니다.

참여 신청

오프라인 밋업은 여기서 참여신청이 가능합니다. https://event-us.kr/hackerspubseoul/event/110961

  • 모집 기간
    • 1차 모집 : 8월 27일 ~ 9월 1일 (Hackers' Pub에서만 모집)
    • 2차 모집 : 9월 3일 ~ 9월 7일 (Hackers' Pub 외부에서도 공개적으로 모집)

주의사항

  • 본 행사는 Hackers' Pub에서 진행하는 오프라인 행사이며, Hackers' Pub 계정을 가지지 않은 분이 신청하셨을 경우 환불처리될 수 있습니다.
  • Hackers' Pub 외부에서 유입하시는 경우, 각 모집기간이 끝나고 24시간 안에는 Hackers' Pub에 가입이 되어 있으셔야 참여자로 확정됩니다.
@hongminhee@hollo.social

New blog post: Bringing parser combinators to CLI parsing with Optique

  • Compose parsers like or(option("-a"), option("-b"))
  • TypeScript infers discriminated unions automatically
  • Inspired by Haskell's optparse-applicative

https://dev.to/hongminhee/optique-type-safe-cli-parser-combinators-39md

dev.to

Optique: Type-Safe CLI Parser Combinators

Recently, I developed a somewhat experimental CLI parser library called Optique. While it has now...