The best Hacker News stories from Show from the past day
Latest posts:
Show HN: Devil Mode: A twisted Emacs key translator for modifier-free editing
Show HN: Git Hooting
00's called, they want their RSS feeds back.<p>I was looking at my growing Github gist collection when a sudden urge to blog and make a name for myself "by not programming" struck. Part way into implementing my oh so special static website generator it occurred to me that, quite frankly, Github gists is a pretty decent publishing platform. I mean, it gives you reasonably extended markdown with previews, heck I could even write in org-mode, has comments, follower - followee relationship, extended search with filters, check out locally and push your edits. Did someone say "edit button"?<p>Thus the idea behind <a href="https://git.ht" rel="nofollow">https://git.ht</a> was born: collect gists into RSS feeds and force everyone, kicking and screaming, into the good old days when Google Reader was king. Well, it's a bit more than that now. But basically, you create a gist or grab an old one, name its main file `hoot.md` or `hoot.org` if org-mode is your poison, make it public and voila. These "hoots" make it into your RSS feed and will get permalinks with social graph metatags, so you get nice previews when you share them on Twitter and such.<p>To take it for a spin:
- pick a subdomain e.g. foo.git.ht,
- navigate you browser there,
- login with Github.<p>I still consider it alpha, but it should work. Report any issues as you would normally on Github <a href="https://github.com/fullmeta-dev/githoot-public">https://github.com/fullmeta-dev/githoot-public</a>.<p>Thank you
Show HN: Git Hooting
00's called, they want their RSS feeds back.<p>I was looking at my growing Github gist collection when a sudden urge to blog and make a name for myself "by not programming" struck. Part way into implementing my oh so special static website generator it occurred to me that, quite frankly, Github gists is a pretty decent publishing platform. I mean, it gives you reasonably extended markdown with previews, heck I could even write in org-mode, has comments, follower - followee relationship, extended search with filters, check out locally and push your edits. Did someone say "edit button"?<p>Thus the idea behind <a href="https://git.ht" rel="nofollow">https://git.ht</a> was born: collect gists into RSS feeds and force everyone, kicking and screaming, into the good old days when Google Reader was king. Well, it's a bit more than that now. But basically, you create a gist or grab an old one, name its main file `hoot.md` or `hoot.org` if org-mode is your poison, make it public and voila. These "hoots" make it into your RSS feed and will get permalinks with social graph metatags, so you get nice previews when you share them on Twitter and such.<p>To take it for a spin:
- pick a subdomain e.g. foo.git.ht,
- navigate you browser there,
- login with Github.<p>I still consider it alpha, but it should work. Report any issues as you would normally on Github <a href="https://github.com/fullmeta-dev/githoot-public">https://github.com/fullmeta-dev/githoot-public</a>.<p>Thank you
Show HN: UnionX – GPT4-powered Copilot for Work with Jupyter-style notebooks
Hey HN community!<p>We're excited to introduce UnionX, an AI Copilot for Work designed to revolutionize the way you perform research, write long documents, and extract insights. Our platform is perfect for PMs, students, lawyers, finance professionals, and more.<p>UnionX is built on cutting-edge technology, leveraging OpenAI's GPT4 model and Jupyter notebook-style workflows to create a seamless, AI-powered experience. Our block-based editor allows you to easily upload documents, analyze them, and generate new insights or docs with the help of AI. If you don't have ideas about what to do with your data, UnionX provides AI Actions that provide common and AI-generated suggestions to help you transform your documents and deliver your work on time.<p>Some key features include:<p>- Jupyter-style notebooks<p>- Document & spreadsheet editors<p>- AI action & chat blocks<p>- Knowledge bases with large document support<p>- Visualizations (coming soon)<p>- Form filling (coming soon)<p>Give our GPT4-powered beta a try for free and let us know what you think!<p>Check it out: <a href="https://unionx.io" rel="nofollow">https://unionx.io</a><p>-David
Show HN: Ethereum address reviews, similar to Yelp
Hi HN,
Excuse me if the formatting sucks, this is a first time post.<p>I want to introduce to you vrfd.info. A place where you can openly view and influence the reputation of any Ethereum address. Think of it as Yelp but for Eth.<p>Addresses are classified as either verified or flagged on-chain through soulbound NFTs. A type of NFT that has no trade value as it cannot be sold. Once minted, it is stuck to the given address. The metadata of the NFT contains either information to verify the address with, this could be a social account for example. Or in the case of flagged addresses, the metadata contains proof of wrong-doing.<p>Users can search the classification status of any address on the web app. Additionally, users can apply to either verify or report an address, provided proof. In the case of reports, users stand a chance to be rewarded. Finally, users can up or down vote other addresses.<p>I made this tool after suffering one to many scam without having an open source library where addresses can be reported or their credentials verified.<p>It's still a bit clunky, but the core concept works fully integrated on the Testnet. I'm shipping a big update this week to make it more responsive.<p>Thanks for taking the time to read this. Please give me any feedback as I am looking to improve everywhere I can.
Show HN: ReRender AI - Realistic Architectural Renders for AutoCAD/Blender Users
Show HN: ReRender AI - Realistic Architectural Renders for AutoCAD/Blender Users
Show HN: Avoiding Imgur Link Rot
Over the last decade I've built a number of different digital asset managers (mostly media files) that met the needs of my companies at the time. It is an area I enjoy working in. A month ago, when asked what was next for me, I jokingly said I would build another DAM.<p>Then on Saturday, two weeks ago, I learnt that Imgur was going to delete all anonymous & NSFW files on the 15th of May. It was pointed out that this would mean broken links in communities that had relied on Imgur. By the Sunday I had decided that I would build another DAM, initially with the intent of avoiding Imgur link rot.<p>It was challenging to find time to spend on this, the project was put together over about 8 evenings. It still has rough patches, this is an early MVP (a Michael Seibel "brick").<p>I have many ideas of where to take this project, but for now it only does one thing: backup Imgur files and produce new links that are easy to swap out for old soon-to-be-deleted Imgur links.
Show HN: On the security of the Linux disk encryption LUKS
In the past few days, there have been uncertainties and concerns about the LUKS (“Linux Unified Key Setup”) disk encryption, which is widely used on Linux. We publish our assessment of this here.
Show HN: Hypertune – Visual, functional, statically-typed configuration language
Hey HN! I'm Miraan, the founder at Hypertune, and I'm excited to be posting this on HN. Hypertune lets you make your code configurable to let teammates like PMs and marketers quickly change feature flags, in-app copy, pricing plans, etc.<p>It's like a CMS but instead of only letting you set static content, you can insert arbitrary logic from the UI, including A/B tests and ML "loops".<p>I previously built a landing page optimization tool that let marketers define variants of their headline, CTA, cover image, etc, then used a genetic algorithm to find the best combination of them. They used my Chrome extension to define changes on DOM elements based on their unique CSS selector. But this broke when the underlying page changed and didn't work with sites that used CSS modules. Developers hated it.<p>I took a step back.<p>The problem I was trying to solve was making the page configurable by marketers in a way that developers liked. I decided to solve it from first principles and this led to Hypertune.<p>Here's how it works. You define a strongly typed configuration schema in GraphQL, e.g.<p><pre><code> type Query {
page(language: Language!, deviceType: DeviceType!): Page!
}
type Page {
headline: String!
imageUrl: String!
showPromotion: Boolean!
benefits: [String!]!
}
enum Language { English, French, Spanish }
enum DeviceType { Desktop, Mobile, Tablet }
</code></pre>
Then marketers can configure these fields from the UI using our visual, functional, statically-typed language. The language UI is <i>type-directed</i> so we only show expression options that satisfy the required type of the hole in the logic tree. So for the "headline" field, you can insert a String expression or an If / Else expression that returns a String. If you insert the latter, more holes appear. This means marketers don't need to know any syntax and can't get into invalid states. They can use arguments you define in the schema like "language" and "deviceType", and drop A/B tests and contextual multi-armed bandits anywhere in their logic. We overlay live counts on the logic tree UI so they can see how often different branches are called.<p>You get the config via our SDK which fetches your logic tree once on initialization (from our CDN) then evaluates it locally so you can get flags or content with different arguments (e.g. for different users) immediately with no network latency. So you can use the SDK on your backend without adding extra latency to every request, or on the frontend without blocking renders. The SDK includes a command line tool that auto-generates code for end-to-end type-safety based on your schema. You can also query your config via the GraphQL API.<p>If you use the SDK, you can also embed a build-time snapshot of your logic tree in your app bundle. The SDK initializes from this instantly then fetches the latest logic from the server. So it'll still work in the unlikely event the CDN is down. And on the frontend, you can evaluate flags, content, A/B tests, personalization logic, etc, instantly on page load without any network latency, which makes it compatible with static Jamstack sites.<p>I started building this for landing pages but realized it could be used for configuring feature flags, in-app content, translations, onboarding flows, permissions, rules, limits, magic numbers, pricing plans, backend services, cron jobs, etc, as it's all just "code configuration".<p>This configuration is usually hardcoded, sprawled across json or yaml files, or in separate platforms for feature flags, content management, A/B testing, pricing plans, etc. So if a PM wants to A/B test new onboarding content, they need a developer to write glue code that stitches their A/B testing tool with their CMS for that specific test, then wait for a code deployment. And at that point, it may not be worth the effort.<p>The general problem with having separate platforms is that all this configuration naturally overlaps. Feature flags and content management overlap with A/B testing and analytics. Pricing plans overlap with feature flags. Keeping them separate leads to inflexibility and duplication and requires hacky glue code, which defeats the purpose of configuration.<p>I think the solution is a flexible, type-safe code configuration platform with a strongly typed schema, type-safe SDKs and APIs, and a visual, functional, statically-typed language with analytics, A/B testing and ML built in. I think this solves the problem with having separate platforms, but also results in a better solution for individual use cases and makes new use cases possible.<p>For example, compared specifically to other feature flag platforms, you get auto-generated type-safe code to catch flag typos and errors at compile-time (instead of run-time), code completion and "find all references" in your IDE (no figuring out if a flag is in kebab-case or camelCase), type-safe enum flags you can exhaustively switch on, type-safe object and list flags, and a type-safe logic UI. You pass context arguments like userId, email, etc, in a type-safe way too with compiler errors if you miss or misspell one. To clean up a flag, you remove it from your query, re-run code generation and fix all the type errors to remove all references. The full programming language under the hood means there are no limits on your flag logic (you're not locked into basic disjunctive normal form). You can embed a build-time snapshot of your flag logic in your app bundle for guaranteed, instant initialization with no network latency (and keep this up to date with a commit webhook). And all your flags are versioned together in a single Git history for instant rollbacks to known good states (no figuring out what combination of flag changes caused an incident).<p>There are other flexible configuration languages like Dhall (discussed here: <a href="https://news.ycombinator.com/item?id=32102203" rel="nofollow">https://news.ycombinator.com/item?id=32102203</a>), Jsonnet (discussed here: <a href="https://news.ycombinator.com/item?id=19656821" rel="nofollow">https://news.ycombinator.com/item?id=19656821</a>) and Cue (discussed here: <a href="https://news.ycombinator.com/item?id=20847943" rel="nofollow">https://news.ycombinator.com/item?id=20847943</a>). But they lack a UI for nontechnical users, can't be updated at run-time and don't support analytics, A/B testing and ML.<p>I was actually going to start with a basic language that had primitives (Boolean, Int, String), a Comparison expression and an If / Else. Then users could implement the logic for each field in the schema separately.<p>But then I realized they might want to share logic for a group of fields at the object level, e.g. instead of repeating "if (deviceType == Mobile) { primitiveA } else { primitiveB }" for each primitive field separately, they could have the logic once at the Page level: "if (deviceType == Mobile) { pageObjectA } else { pageObjectB }". I also needed to represent field arguments like "deviceType" in the language. And I realized users may want to define other variables to reuse bits of logic, like a specific "benefit" which appears in different variations of the "benefits" list.<p>So at this point, it made sense to build a full, functional language with Object expressions (that have a type defined in the schema) and Function, Variable and Application expressions (to implement the lambda calculus). Then all the configuration can be represented as a single Object with the root Query type from the schema, e.g.<p><pre><code> Query {
page: f({ deviceType }) =>
switch (true) {
case (deviceType == DeviceType.Mobile) =>
Page {
headline: f({}) => "Headline A"
imageUrl: f({}) => "Image A"
showPromotion: f({}) => true
benefits: f({}) => ["Ben", "efits", "A"]
}
default =>
Page {
headline: f({}) => "Headline B"
imageUrl: f({}) => "Image B"
showPromotion: f({}) => false
benefits: f({}) => ["Ben", "efits", "B"]
}
}
}
</code></pre>
So each schema field is implemented by a Function that takes a single Object parameter (a dictionary of field argument name => value). I needed to evaluate this logic tree given a GraphQL query that looks like:<p><pre><code> query {
page(deviceType: Mobile) {
headline
showPromotion
}
}
</code></pre>
So I built an interpreter that recursively selects the queried parts of the logic tree, evaluating the Functions for each query field with the given arguments. It ignores fields that aren't in the query so the logic tree can grow large without affecting query performance.<p>The interpreter is used by the SDK, to evaluate logic locally, and on our CDN edge server that hosts the GraphQL API. The response for the example above would be:<p><pre><code> {
"__typename": "Query",
"page": {
"__typename": "Page",
"headline": "Headline A",
"showPromotion": true
}
}
</code></pre>
Developers were concerned about using the SDK on the frontend as it could leak sensitive configuration logic, like lists of user IDs, to the browser.<p>To solve this, I modified the interpreter to support "partial evaluation". This is where it takes a GraphQL query that only provides some of the required field arguments and then partially evaluates the logic tree as much as possible. Any logic which can't be evaluated is left intact.<p>The SDK can leverage this at initialization time by passing already known arguments (e.g. the user ID) in its initialization query so that sensitive logic (like lists of user IDs) are evaluated (and eliminated) on the server. The rest of the logic is evaluated locally by the SDK when client code calls its methods with the remaining arguments. This also minimizes the payload size sent to the client and means less logic needs to be evaluated locally, which improves both page load and render performance.<p>The interpreter also keeps a count of expression evaluations as well as events for A/B tests and ML loops, which are flushed back to Hypertune in the background to overlay live analytics on the logic tree UI.<p>It's been a challenge to build a simple UI given there's a full functional language under the hood. For example, I needed to build a way for users to convert any expression into a variable in one click. Under the hood, to make expression X a variable, we wrap the parent of X in a Function that takes a single parameter, then wrap that Function in an Application that passes X as an argument. Then we replace X in the Function body with a reference to the parameter. So we go from:<p><pre><code> if (X) {
Y
} else {
Z
}
</code></pre>
to<p><pre><code> ((paramX) =>
if (paramX) {
Y
} else {
Z
}
)(X)
</code></pre>
So a variable is just an Application argument that can be referenced in the called Function's body. And once we have a variable, we can reference it in more than one place in the Function body. To undo this, users can "drop" a variable in one click which replaces all its references with a copy of its value.<p>Converting X into a variable gets more tricky if the parent of X is a Function itself which defines parameters referenced inside of X. In this case, when we make X a variable, we lift it outside of this Function. But then it doesn't have access to the Function's parameters anymore. So we automatically convert X into a Function itself which takes the parameters it needs. Then we call this new Function where we originally had X, passing in the original parameters. There are more interesting details about how we lift variables to higher scopes in one click but that's for another post.<p>Thanks for reading this far! I'm glad I got to share Hypertune with you. I'm curious about what use case appeals to you the most. Is it type-safe feature flags, in-app content management, A/B testing static Jamstack sites, managing permissions, pricing plans or something else? Please let me know any thoughts or questions!
Show HN: Hypertune – Visual, functional, statically-typed configuration language
Hey HN! I'm Miraan, the founder at Hypertune, and I'm excited to be posting this on HN. Hypertune lets you make your code configurable to let teammates like PMs and marketers quickly change feature flags, in-app copy, pricing plans, etc.<p>It's like a CMS but instead of only letting you set static content, you can insert arbitrary logic from the UI, including A/B tests and ML "loops".<p>I previously built a landing page optimization tool that let marketers define variants of their headline, CTA, cover image, etc, then used a genetic algorithm to find the best combination of them. They used my Chrome extension to define changes on DOM elements based on their unique CSS selector. But this broke when the underlying page changed and didn't work with sites that used CSS modules. Developers hated it.<p>I took a step back.<p>The problem I was trying to solve was making the page configurable by marketers in a way that developers liked. I decided to solve it from first principles and this led to Hypertune.<p>Here's how it works. You define a strongly typed configuration schema in GraphQL, e.g.<p><pre><code> type Query {
page(language: Language!, deviceType: DeviceType!): Page!
}
type Page {
headline: String!
imageUrl: String!
showPromotion: Boolean!
benefits: [String!]!
}
enum Language { English, French, Spanish }
enum DeviceType { Desktop, Mobile, Tablet }
</code></pre>
Then marketers can configure these fields from the UI using our visual, functional, statically-typed language. The language UI is <i>type-directed</i> so we only show expression options that satisfy the required type of the hole in the logic tree. So for the "headline" field, you can insert a String expression or an If / Else expression that returns a String. If you insert the latter, more holes appear. This means marketers don't need to know any syntax and can't get into invalid states. They can use arguments you define in the schema like "language" and "deviceType", and drop A/B tests and contextual multi-armed bandits anywhere in their logic. We overlay live counts on the logic tree UI so they can see how often different branches are called.<p>You get the config via our SDK which fetches your logic tree once on initialization (from our CDN) then evaluates it locally so you can get flags or content with different arguments (e.g. for different users) immediately with no network latency. So you can use the SDK on your backend without adding extra latency to every request, or on the frontend without blocking renders. The SDK includes a command line tool that auto-generates code for end-to-end type-safety based on your schema. You can also query your config via the GraphQL API.<p>If you use the SDK, you can also embed a build-time snapshot of your logic tree in your app bundle. The SDK initializes from this instantly then fetches the latest logic from the server. So it'll still work in the unlikely event the CDN is down. And on the frontend, you can evaluate flags, content, A/B tests, personalization logic, etc, instantly on page load without any network latency, which makes it compatible with static Jamstack sites.<p>I started building this for landing pages but realized it could be used for configuring feature flags, in-app content, translations, onboarding flows, permissions, rules, limits, magic numbers, pricing plans, backend services, cron jobs, etc, as it's all just "code configuration".<p>This configuration is usually hardcoded, sprawled across json or yaml files, or in separate platforms for feature flags, content management, A/B testing, pricing plans, etc. So if a PM wants to A/B test new onboarding content, they need a developer to write glue code that stitches their A/B testing tool with their CMS for that specific test, then wait for a code deployment. And at that point, it may not be worth the effort.<p>The general problem with having separate platforms is that all this configuration naturally overlaps. Feature flags and content management overlap with A/B testing and analytics. Pricing plans overlap with feature flags. Keeping them separate leads to inflexibility and duplication and requires hacky glue code, which defeats the purpose of configuration.<p>I think the solution is a flexible, type-safe code configuration platform with a strongly typed schema, type-safe SDKs and APIs, and a visual, functional, statically-typed language with analytics, A/B testing and ML built in. I think this solves the problem with having separate platforms, but also results in a better solution for individual use cases and makes new use cases possible.<p>For example, compared specifically to other feature flag platforms, you get auto-generated type-safe code to catch flag typos and errors at compile-time (instead of run-time), code completion and "find all references" in your IDE (no figuring out if a flag is in kebab-case or camelCase), type-safe enum flags you can exhaustively switch on, type-safe object and list flags, and a type-safe logic UI. You pass context arguments like userId, email, etc, in a type-safe way too with compiler errors if you miss or misspell one. To clean up a flag, you remove it from your query, re-run code generation and fix all the type errors to remove all references. The full programming language under the hood means there are no limits on your flag logic (you're not locked into basic disjunctive normal form). You can embed a build-time snapshot of your flag logic in your app bundle for guaranteed, instant initialization with no network latency (and keep this up to date with a commit webhook). And all your flags are versioned together in a single Git history for instant rollbacks to known good states (no figuring out what combination of flag changes caused an incident).<p>There are other flexible configuration languages like Dhall (discussed here: <a href="https://news.ycombinator.com/item?id=32102203" rel="nofollow">https://news.ycombinator.com/item?id=32102203</a>), Jsonnet (discussed here: <a href="https://news.ycombinator.com/item?id=19656821" rel="nofollow">https://news.ycombinator.com/item?id=19656821</a>) and Cue (discussed here: <a href="https://news.ycombinator.com/item?id=20847943" rel="nofollow">https://news.ycombinator.com/item?id=20847943</a>). But they lack a UI for nontechnical users, can't be updated at run-time and don't support analytics, A/B testing and ML.<p>I was actually going to start with a basic language that had primitives (Boolean, Int, String), a Comparison expression and an If / Else. Then users could implement the logic for each field in the schema separately.<p>But then I realized they might want to share logic for a group of fields at the object level, e.g. instead of repeating "if (deviceType == Mobile) { primitiveA } else { primitiveB }" for each primitive field separately, they could have the logic once at the Page level: "if (deviceType == Mobile) { pageObjectA } else { pageObjectB }". I also needed to represent field arguments like "deviceType" in the language. And I realized users may want to define other variables to reuse bits of logic, like a specific "benefit" which appears in different variations of the "benefits" list.<p>So at this point, it made sense to build a full, functional language with Object expressions (that have a type defined in the schema) and Function, Variable and Application expressions (to implement the lambda calculus). Then all the configuration can be represented as a single Object with the root Query type from the schema, e.g.<p><pre><code> Query {
page: f({ deviceType }) =>
switch (true) {
case (deviceType == DeviceType.Mobile) =>
Page {
headline: f({}) => "Headline A"
imageUrl: f({}) => "Image A"
showPromotion: f({}) => true
benefits: f({}) => ["Ben", "efits", "A"]
}
default =>
Page {
headline: f({}) => "Headline B"
imageUrl: f({}) => "Image B"
showPromotion: f({}) => false
benefits: f({}) => ["Ben", "efits", "B"]
}
}
}
</code></pre>
So each schema field is implemented by a Function that takes a single Object parameter (a dictionary of field argument name => value). I needed to evaluate this logic tree given a GraphQL query that looks like:<p><pre><code> query {
page(deviceType: Mobile) {
headline
showPromotion
}
}
</code></pre>
So I built an interpreter that recursively selects the queried parts of the logic tree, evaluating the Functions for each query field with the given arguments. It ignores fields that aren't in the query so the logic tree can grow large without affecting query performance.<p>The interpreter is used by the SDK, to evaluate logic locally, and on our CDN edge server that hosts the GraphQL API. The response for the example above would be:<p><pre><code> {
"__typename": "Query",
"page": {
"__typename": "Page",
"headline": "Headline A",
"showPromotion": true
}
}
</code></pre>
Developers were concerned about using the SDK on the frontend as it could leak sensitive configuration logic, like lists of user IDs, to the browser.<p>To solve this, I modified the interpreter to support "partial evaluation". This is where it takes a GraphQL query that only provides some of the required field arguments and then partially evaluates the logic tree as much as possible. Any logic which can't be evaluated is left intact.<p>The SDK can leverage this at initialization time by passing already known arguments (e.g. the user ID) in its initialization query so that sensitive logic (like lists of user IDs) are evaluated (and eliminated) on the server. The rest of the logic is evaluated locally by the SDK when client code calls its methods with the remaining arguments. This also minimizes the payload size sent to the client and means less logic needs to be evaluated locally, which improves both page load and render performance.<p>The interpreter also keeps a count of expression evaluations as well as events for A/B tests and ML loops, which are flushed back to Hypertune in the background to overlay live analytics on the logic tree UI.<p>It's been a challenge to build a simple UI given there's a full functional language under the hood. For example, I needed to build a way for users to convert any expression into a variable in one click. Under the hood, to make expression X a variable, we wrap the parent of X in a Function that takes a single parameter, then wrap that Function in an Application that passes X as an argument. Then we replace X in the Function body with a reference to the parameter. So we go from:<p><pre><code> if (X) {
Y
} else {
Z
}
</code></pre>
to<p><pre><code> ((paramX) =>
if (paramX) {
Y
} else {
Z
}
)(X)
</code></pre>
So a variable is just an Application argument that can be referenced in the called Function's body. And once we have a variable, we can reference it in more than one place in the Function body. To undo this, users can "drop" a variable in one click which replaces all its references with a copy of its value.<p>Converting X into a variable gets more tricky if the parent of X is a Function itself which defines parameters referenced inside of X. In this case, when we make X a variable, we lift it outside of this Function. But then it doesn't have access to the Function's parameters anymore. So we automatically convert X into a Function itself which takes the parameters it needs. Then we call this new Function where we originally had X, passing in the original parameters. There are more interesting details about how we lift variables to higher scopes in one click but that's for another post.<p>Thanks for reading this far! I'm glad I got to share Hypertune with you. I'm curious about what use case appeals to you the most. Is it type-safe feature flags, in-app content management, A/B testing static Jamstack sites, managing permissions, pricing plans or something else? Please let me know any thoughts or questions!
Show HN: Hypertune – Visual, functional, statically-typed configuration language
Hey HN! I'm Miraan, the founder at Hypertune, and I'm excited to be posting this on HN. Hypertune lets you make your code configurable to let teammates like PMs and marketers quickly change feature flags, in-app copy, pricing plans, etc.<p>It's like a CMS but instead of only letting you set static content, you can insert arbitrary logic from the UI, including A/B tests and ML "loops".<p>I previously built a landing page optimization tool that let marketers define variants of their headline, CTA, cover image, etc, then used a genetic algorithm to find the best combination of them. They used my Chrome extension to define changes on DOM elements based on their unique CSS selector. But this broke when the underlying page changed and didn't work with sites that used CSS modules. Developers hated it.<p>I took a step back.<p>The problem I was trying to solve was making the page configurable by marketers in a way that developers liked. I decided to solve it from first principles and this led to Hypertune.<p>Here's how it works. You define a strongly typed configuration schema in GraphQL, e.g.<p><pre><code> type Query {
page(language: Language!, deviceType: DeviceType!): Page!
}
type Page {
headline: String!
imageUrl: String!
showPromotion: Boolean!
benefits: [String!]!
}
enum Language { English, French, Spanish }
enum DeviceType { Desktop, Mobile, Tablet }
</code></pre>
Then marketers can configure these fields from the UI using our visual, functional, statically-typed language. The language UI is <i>type-directed</i> so we only show expression options that satisfy the required type of the hole in the logic tree. So for the "headline" field, you can insert a String expression or an If / Else expression that returns a String. If you insert the latter, more holes appear. This means marketers don't need to know any syntax and can't get into invalid states. They can use arguments you define in the schema like "language" and "deviceType", and drop A/B tests and contextual multi-armed bandits anywhere in their logic. We overlay live counts on the logic tree UI so they can see how often different branches are called.<p>You get the config via our SDK which fetches your logic tree once on initialization (from our CDN) then evaluates it locally so you can get flags or content with different arguments (e.g. for different users) immediately with no network latency. So you can use the SDK on your backend without adding extra latency to every request, or on the frontend without blocking renders. The SDK includes a command line tool that auto-generates code for end-to-end type-safety based on your schema. You can also query your config via the GraphQL API.<p>If you use the SDK, you can also embed a build-time snapshot of your logic tree in your app bundle. The SDK initializes from this instantly then fetches the latest logic from the server. So it'll still work in the unlikely event the CDN is down. And on the frontend, you can evaluate flags, content, A/B tests, personalization logic, etc, instantly on page load without any network latency, which makes it compatible with static Jamstack sites.<p>I started building this for landing pages but realized it could be used for configuring feature flags, in-app content, translations, onboarding flows, permissions, rules, limits, magic numbers, pricing plans, backend services, cron jobs, etc, as it's all just "code configuration".<p>This configuration is usually hardcoded, sprawled across json or yaml files, or in separate platforms for feature flags, content management, A/B testing, pricing plans, etc. So if a PM wants to A/B test new onboarding content, they need a developer to write glue code that stitches their A/B testing tool with their CMS for that specific test, then wait for a code deployment. And at that point, it may not be worth the effort.<p>The general problem with having separate platforms is that all this configuration naturally overlaps. Feature flags and content management overlap with A/B testing and analytics. Pricing plans overlap with feature flags. Keeping them separate leads to inflexibility and duplication and requires hacky glue code, which defeats the purpose of configuration.<p>I think the solution is a flexible, type-safe code configuration platform with a strongly typed schema, type-safe SDKs and APIs, and a visual, functional, statically-typed language with analytics, A/B testing and ML built in. I think this solves the problem with having separate platforms, but also results in a better solution for individual use cases and makes new use cases possible.<p>For example, compared specifically to other feature flag platforms, you get auto-generated type-safe code to catch flag typos and errors at compile-time (instead of run-time), code completion and "find all references" in your IDE (no figuring out if a flag is in kebab-case or camelCase), type-safe enum flags you can exhaustively switch on, type-safe object and list flags, and a type-safe logic UI. You pass context arguments like userId, email, etc, in a type-safe way too with compiler errors if you miss or misspell one. To clean up a flag, you remove it from your query, re-run code generation and fix all the type errors to remove all references. The full programming language under the hood means there are no limits on your flag logic (you're not locked into basic disjunctive normal form). You can embed a build-time snapshot of your flag logic in your app bundle for guaranteed, instant initialization with no network latency (and keep this up to date with a commit webhook). And all your flags are versioned together in a single Git history for instant rollbacks to known good states (no figuring out what combination of flag changes caused an incident).<p>There are other flexible configuration languages like Dhall (discussed here: <a href="https://news.ycombinator.com/item?id=32102203" rel="nofollow">https://news.ycombinator.com/item?id=32102203</a>), Jsonnet (discussed here: <a href="https://news.ycombinator.com/item?id=19656821" rel="nofollow">https://news.ycombinator.com/item?id=19656821</a>) and Cue (discussed here: <a href="https://news.ycombinator.com/item?id=20847943" rel="nofollow">https://news.ycombinator.com/item?id=20847943</a>). But they lack a UI for nontechnical users, can't be updated at run-time and don't support analytics, A/B testing and ML.<p>I was actually going to start with a basic language that had primitives (Boolean, Int, String), a Comparison expression and an If / Else. Then users could implement the logic for each field in the schema separately.<p>But then I realized they might want to share logic for a group of fields at the object level, e.g. instead of repeating "if (deviceType == Mobile) { primitiveA } else { primitiveB }" for each primitive field separately, they could have the logic once at the Page level: "if (deviceType == Mobile) { pageObjectA } else { pageObjectB }". I also needed to represent field arguments like "deviceType" in the language. And I realized users may want to define other variables to reuse bits of logic, like a specific "benefit" which appears in different variations of the "benefits" list.<p>So at this point, it made sense to build a full, functional language with Object expressions (that have a type defined in the schema) and Function, Variable and Application expressions (to implement the lambda calculus). Then all the configuration can be represented as a single Object with the root Query type from the schema, e.g.<p><pre><code> Query {
page: f({ deviceType }) =>
switch (true) {
case (deviceType == DeviceType.Mobile) =>
Page {
headline: f({}) => "Headline A"
imageUrl: f({}) => "Image A"
showPromotion: f({}) => true
benefits: f({}) => ["Ben", "efits", "A"]
}
default =>
Page {
headline: f({}) => "Headline B"
imageUrl: f({}) => "Image B"
showPromotion: f({}) => false
benefits: f({}) => ["Ben", "efits", "B"]
}
}
}
</code></pre>
So each schema field is implemented by a Function that takes a single Object parameter (a dictionary of field argument name => value). I needed to evaluate this logic tree given a GraphQL query that looks like:<p><pre><code> query {
page(deviceType: Mobile) {
headline
showPromotion
}
}
</code></pre>
So I built an interpreter that recursively selects the queried parts of the logic tree, evaluating the Functions for each query field with the given arguments. It ignores fields that aren't in the query so the logic tree can grow large without affecting query performance.<p>The interpreter is used by the SDK, to evaluate logic locally, and on our CDN edge server that hosts the GraphQL API. The response for the example above would be:<p><pre><code> {
"__typename": "Query",
"page": {
"__typename": "Page",
"headline": "Headline A",
"showPromotion": true
}
}
</code></pre>
Developers were concerned about using the SDK on the frontend as it could leak sensitive configuration logic, like lists of user IDs, to the browser.<p>To solve this, I modified the interpreter to support "partial evaluation". This is where it takes a GraphQL query that only provides some of the required field arguments and then partially evaluates the logic tree as much as possible. Any logic which can't be evaluated is left intact.<p>The SDK can leverage this at initialization time by passing already known arguments (e.g. the user ID) in its initialization query so that sensitive logic (like lists of user IDs) are evaluated (and eliminated) on the server. The rest of the logic is evaluated locally by the SDK when client code calls its methods with the remaining arguments. This also minimizes the payload size sent to the client and means less logic needs to be evaluated locally, which improves both page load and render performance.<p>The interpreter also keeps a count of expression evaluations as well as events for A/B tests and ML loops, which are flushed back to Hypertune in the background to overlay live analytics on the logic tree UI.<p>It's been a challenge to build a simple UI given there's a full functional language under the hood. For example, I needed to build a way for users to convert any expression into a variable in one click. Under the hood, to make expression X a variable, we wrap the parent of X in a Function that takes a single parameter, then wrap that Function in an Application that passes X as an argument. Then we replace X in the Function body with a reference to the parameter. So we go from:<p><pre><code> if (X) {
Y
} else {
Z
}
</code></pre>
to<p><pre><code> ((paramX) =>
if (paramX) {
Y
} else {
Z
}
)(X)
</code></pre>
So a variable is just an Application argument that can be referenced in the called Function's body. And once we have a variable, we can reference it in more than one place in the Function body. To undo this, users can "drop" a variable in one click which replaces all its references with a copy of its value.<p>Converting X into a variable gets more tricky if the parent of X is a Function itself which defines parameters referenced inside of X. In this case, when we make X a variable, we lift it outside of this Function. But then it doesn't have access to the Function's parameters anymore. So we automatically convert X into a Function itself which takes the parameters it needs. Then we call this new Function where we originally had X, passing in the original parameters. There are more interesting details about how we lift variables to higher scopes in one click but that's for another post.<p>Thanks for reading this far! I'm glad I got to share Hypertune with you. I'm curious about what use case appeals to you the most. Is it type-safe feature flags, in-app content management, A/B testing static Jamstack sites, managing permissions, pricing plans or something else? Please let me know any thoughts or questions!
Show HN: Make domain verification as easy as verifying an email or phone number
Hi HN,<p>This is a project [1] I've been working on for a little while and I'm interested in your feedback and point of view.<p>Many of us would have verified a domain name by pasting a string into a DNS TXT record. Some providers ask us to store this DNS TXT record at a domain using a DNS label like "_provider" e.g. _provider.yourdomain.com, and some providers ask that you do it at the zone apex (God help us [2]).<p>The Domain Verification protocol stores a DNS TXT record at a DNS name derived from a hashed "verifiable identifier" (think email, telephone, DID), enabling anyone that can prove control over the verifiable identifier to prove authority for the domain name.<p>For example, the domain verification record giving the email address user@example.com authority over the domain dvexample.com can be seen with this terminal command:<p>dig 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com TXT<p>The record can specify what type of services the authorised party is allowed to use (e.g. SEO, Storage, Advertising) or specify an exact provider (ads.google.com), you can also specify an expiry date.<p>The benefits of this approach are:<p>- Domain owners can grant time-limited, granular permissions for third parties to verify a domain<p>- Every service provider could use the same verification record<p>- Once a domain owner creates a verification record by following instructions from one service provider, that same record could be used by other service providers<p>- Domain registrars could set these records up on behalf of users, perhaps even upon domain registration (with registrant opt-in). This would provide domain registrants with a fast lane for signing up to services like Google Ads, Facebook Ads, Dropbox, whatever<p>I'm still working on licensing but creating these records will always be free. I hope to find service providers that see significant upside in reducing friction for user onboarding that are willing to pay to license it.<p>Worked example:
Let's say you want to authenticate the user with the email user@example.com with the domain dvexample.com, these are the steps:<p>1. HASH(user@example.com) -> 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>2. Store Domain Verification record at:
4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com<p>3. TXT record determines permissions and time limit:<p>@dv=1;d=Example user emali;e=2025-01-01;s=[seo;email];h=4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>BTW, if you're interested the syntax of that DNS record is a compact data serialisation format I created especially for DNS [3].<p>Thanks for taking a look,<p>Elliott<p>1. <a href="https://www.domainverification.org" rel="nofollow">https://www.domainverification.org</a><p>2. dig target.com TXT<p>3. <a href="https://www.compactdata.org" rel="nofollow">https://www.compactdata.org</a><p>(edit: formatting)
Show HN: Make domain verification as easy as verifying an email or phone number
Hi HN,<p>This is a project [1] I've been working on for a little while and I'm interested in your feedback and point of view.<p>Many of us would have verified a domain name by pasting a string into a DNS TXT record. Some providers ask us to store this DNS TXT record at a domain using a DNS label like "_provider" e.g. _provider.yourdomain.com, and some providers ask that you do it at the zone apex (God help us [2]).<p>The Domain Verification protocol stores a DNS TXT record at a DNS name derived from a hashed "verifiable identifier" (think email, telephone, DID), enabling anyone that can prove control over the verifiable identifier to prove authority for the domain name.<p>For example, the domain verification record giving the email address user@example.com authority over the domain dvexample.com can be seen with this terminal command:<p>dig 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com TXT<p>The record can specify what type of services the authorised party is allowed to use (e.g. SEO, Storage, Advertising) or specify an exact provider (ads.google.com), you can also specify an expiry date.<p>The benefits of this approach are:<p>- Domain owners can grant time-limited, granular permissions for third parties to verify a domain<p>- Every service provider could use the same verification record<p>- Once a domain owner creates a verification record by following instructions from one service provider, that same record could be used by other service providers<p>- Domain registrars could set these records up on behalf of users, perhaps even upon domain registration (with registrant opt-in). This would provide domain registrants with a fast lane for signing up to services like Google Ads, Facebook Ads, Dropbox, whatever<p>I'm still working on licensing but creating these records will always be free. I hope to find service providers that see significant upside in reducing friction for user onboarding that are willing to pay to license it.<p>Worked example:
Let's say you want to authenticate the user with the email user@example.com with the domain dvexample.com, these are the steps:<p>1. HASH(user@example.com) -> 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>2. Store Domain Verification record at:
4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com<p>3. TXT record determines permissions and time limit:<p>@dv=1;d=Example user emali;e=2025-01-01;s=[seo;email];h=4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>BTW, if you're interested the syntax of that DNS record is a compact data serialisation format I created especially for DNS [3].<p>Thanks for taking a look,<p>Elliott<p>1. <a href="https://www.domainverification.org" rel="nofollow">https://www.domainverification.org</a><p>2. dig target.com TXT<p>3. <a href="https://www.compactdata.org" rel="nofollow">https://www.compactdata.org</a><p>(edit: formatting)
Show HN: Make domain verification as easy as verifying an email or phone number
Hi HN,<p>This is a project [1] I've been working on for a little while and I'm interested in your feedback and point of view.<p>Many of us would have verified a domain name by pasting a string into a DNS TXT record. Some providers ask us to store this DNS TXT record at a domain using a DNS label like "_provider" e.g. _provider.yourdomain.com, and some providers ask that you do it at the zone apex (God help us [2]).<p>The Domain Verification protocol stores a DNS TXT record at a DNS name derived from a hashed "verifiable identifier" (think email, telephone, DID), enabling anyone that can prove control over the verifiable identifier to prove authority for the domain name.<p>For example, the domain verification record giving the email address user@example.com authority over the domain dvexample.com can be seen with this terminal command:<p>dig 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com TXT<p>The record can specify what type of services the authorised party is allowed to use (e.g. SEO, Storage, Advertising) or specify an exact provider (ads.google.com), you can also specify an expiry date.<p>The benefits of this approach are:<p>- Domain owners can grant time-limited, granular permissions for third parties to verify a domain<p>- Every service provider could use the same verification record<p>- Once a domain owner creates a verification record by following instructions from one service provider, that same record could be used by other service providers<p>- Domain registrars could set these records up on behalf of users, perhaps even upon domain registration (with registrant opt-in). This would provide domain registrants with a fast lane for signing up to services like Google Ads, Facebook Ads, Dropbox, whatever<p>I'm still working on licensing but creating these records will always be free. I hope to find service providers that see significant upside in reducing friction for user onboarding that are willing to pay to license it.<p>Worked example:
Let's say you want to authenticate the user with the email user@example.com with the domain dvexample.com, these are the steps:<p>1. HASH(user@example.com) -> 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>2. Store Domain Verification record at:
4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com<p>3. TXT record determines permissions and time limit:<p>@dv=1;d=Example user emali;e=2025-01-01;s=[seo;email];h=4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>BTW, if you're interested the syntax of that DNS record is a compact data serialisation format I created especially for DNS [3].<p>Thanks for taking a look,<p>Elliott<p>1. <a href="https://www.domainverification.org" rel="nofollow">https://www.domainverification.org</a><p>2. dig target.com TXT<p>3. <a href="https://www.compactdata.org" rel="nofollow">https://www.compactdata.org</a><p>(edit: formatting)
Show HN: Make domain verification as easy as verifying an email or phone number
Hi HN,<p>This is a project [1] I've been working on for a little while and I'm interested in your feedback and point of view.<p>Many of us would have verified a domain name by pasting a string into a DNS TXT record. Some providers ask us to store this DNS TXT record at a domain using a DNS label like "_provider" e.g. _provider.yourdomain.com, and some providers ask that you do it at the zone apex (God help us [2]).<p>The Domain Verification protocol stores a DNS TXT record at a DNS name derived from a hashed "verifiable identifier" (think email, telephone, DID), enabling anyone that can prove control over the verifiable identifier to prove authority for the domain name.<p>For example, the domain verification record giving the email address user@example.com authority over the domain dvexample.com can be seen with this terminal command:<p>dig 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com TXT<p>The record can specify what type of services the authorised party is allowed to use (e.g. SEO, Storage, Advertising) or specify an exact provider (ads.google.com), you can also specify an expiry date.<p>The benefits of this approach are:<p>- Domain owners can grant time-limited, granular permissions for third parties to verify a domain<p>- Every service provider could use the same verification record<p>- Once a domain owner creates a verification record by following instructions from one service provider, that same record could be used by other service providers<p>- Domain registrars could set these records up on behalf of users, perhaps even upon domain registration (with registrant opt-in). This would provide domain registrants with a fast lane for signing up to services like Google Ads, Facebook Ads, Dropbox, whatever<p>I'm still working on licensing but creating these records will always be free. I hope to find service providers that see significant upside in reducing friction for user onboarding that are willing to pay to license it.<p>Worked example:
Let's say you want to authenticate the user with the email user@example.com with the domain dvexample.com, these are the steps:<p>1. HASH(user@example.com) -> 4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>2. Store Domain Verification record at:
4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg._dv.dvexample.com<p>3. TXT record determines permissions and time limit:<p>@dv=1;d=Example user emali;e=2025-01-01;s=[seo;email];h=4i7ozur385y5nsqoo0mg0mxv6t9333s2rarxrtvlpag1gsk8pg<p>BTW, if you're interested the syntax of that DNS record is a compact data serialisation format I created especially for DNS [3].<p>Thanks for taking a look,<p>Elliott<p>1. <a href="https://www.domainverification.org" rel="nofollow">https://www.domainverification.org</a><p>2. dig target.com TXT<p>3. <a href="https://www.compactdata.org" rel="nofollow">https://www.compactdata.org</a><p>(edit: formatting)
Show HN: Remove sponsored content in YouTube videos
Show HN: The HN Recap – AI generated daily HN podcast
We've been running The HN Recap for a month to make it easier to consume Hacker News. While this was a PoC in understanding adoption for AI-generated podcasts, we now plan to keep this going, since lots of people are now listening to this daily.<p>Let us know what other content channels you'd like to receive as Podcasts and we'll get on it.<p>Read more about our learnings here → <a href="https://wondercraft.ai/blog/learnings-from-1-month-of-ai-podcast">https://wondercraft.ai/blog/learnings-from-1-month-of-ai-pod...</a>
Show HN: The HN Recap – AI generated daily HN podcast
We've been running The HN Recap for a month to make it easier to consume Hacker News. While this was a PoC in understanding adoption for AI-generated podcasts, we now plan to keep this going, since lots of people are now listening to this daily.<p>Let us know what other content channels you'd like to receive as Podcasts and we'll get on it.<p>Read more about our learnings here → <a href="https://wondercraft.ai/blog/learnings-from-1-month-of-ai-podcast">https://wondercraft.ai/blog/learnings-from-1-month-of-ai-pod...</a>
Show HN: A search engine for your personal network of high-quality websites
Hey all,<p>Last time when we were on HackerNews [1], we received a lot of feedback, and we incorporated most of it.<p>- We have changed our name from grep.help to usegrasp.com<p>- A privacy policy page<p>- Bulk import<p>- Pricing page<p>We are happy to introduce a new feature: a personalized answer search engine that provides direct citations to the content on the page.<p>Demo: <a href="https://usegrasp.com/search?q=is+starship+fully+reusable?" rel="nofollow">https://usegrasp.com/search?q=is+starship+fully+reusable?</a><p>1 - <a href="https://news.ycombinator.com/item?id=35510949" rel="nofollow">https://news.ycombinator.com/item?id=35510949</a>