@movq@www.uninformativ.de So the way this works in my design/prototype is this. You fork my repo in the app, it clones it to your own forge, follows my instance and it’s repo for updates and ping my instance to indicate “you’ve forked me”. Then when you publish changes, I can see them by pulling your instance’s feed. It all works on the same plain text principles of Tstxt itself. The feeds are “pull”-based with push-based “pings” on things like “someone forked your repo”, “a new issue has been raised against your repo”, etc.
@Sumomo@sumomo.neocities.org Ahh if you’re using the ‘ol twtxt client from buckket, that thing isn’t really maintained anymore. I recommend you check out one of the clients listed on https://twtxt.dev or even just https://twtxt.app
@jastas@twtpub.com Out of curiosity, was it hard to figure that out, or just familiarity with the app? 🤔
@arg@twtpub.com You actually can, but we highly discourage it and I haven’t really built “Edit” / “Delete” functionality in the Twtxt App that I know you’re using 😅 Twtxt being purely decentralised, meaning that there are absolutely zero decentralised, with the exception of the twtpub.com service you’re using to reduce as much friction as possible for newcomers to try things, makes supporting threads a bit of a controversial topic 😆 – In the end we are sticking with the Hash v2 extension, making threads use content addressing, so even if you did delete/edit a Twt, you have to be carefuly it hasn’t already been replied to in the ecosystem 🤣
but yes, however you cannot currently add it or delete post via the app as I haven’t really built that feature at the moment you technically can do it, but you do run into some challenges with breaking threads if you’ve already published something and then go back and edit it so we generally advise not to do that too much if you can help it
@brytboi@twtpub.com I hope you’re seeing my replies because you absolutely can scroll up in the app. Let me know if you’ve run into a bug though and report it to me so I can fix it immediately!
@brytboi@twtpub.com no a subset of markdown is fully supported by the app!
I’m not seeing any of what you’re describing, But then again I only use the app on mobile, on iPhone. There’s only been basically a few commits to the App and one to Swag. That’s it.
@GabesArcade@gabesarcade.com Not sure if @mariam@twtpub.com will ever see or respond to our welcomes tbh 😢 I caught the new user trying out the Twtxt App 4 days too left 🤦♂️ – I think I need to make some improvements to the app, some nudges, something to encourage users to stick around? Maybe some periodic push notifications? 🤔
@david@daiwei.me Also if you wouldn’t mind writing up an Issue for the image/upload problem too, that would be great 👍 I still haven’t solved it properly, but I’ll try to do so today. There’s also an issue uploading images via the yarnd API path from the Twtxt App too, which I can replicate with basically any photo from my iPhone’s Photo gallery hmm 🤔
@david@daiwei.me Ahhh so you had a WebP you downloaded from somewhere on your Phone and you’re trying to uploaded it via the Twtxt.App? 🤔
@javivf@adn.org.es Oh, I like the looks of that.
GTD was undoubtedly the best developed task-management system I ever got into (and I tried a bunch in my time), but even it wound up being too much work for me to keep up with. An app like that might streamline it enough to make it usable. Thanks for the link!
I’m truly in love with Mindwtr, I hope I can keep my self in the GTD loop again :)
@david@daiwei.me if you have some weekend home type place, with no Internet, getting TV through an antenna and a DVBT box, my recommendation is to just buy some old Dell monitor with HDMI to 3.5mm audio output built in, so you can connect speakers to it.
Doesn’t have to be Dell, but you can often just buy one of those from your employer, for under $25 here.
Were this sadly makes much less sense, in with Internet TV services. Those usually need a dedicated TV app to function and while that can be replaced with a $200 TV box, that some providers force you to rent, thus making you pay more for your Internet TV forever - this also means giving up the “archive app”, that gives you access to all the on demand content, included in the price of your mandatory TV license. None of these overpriced boxes come with it, as they’d mauch rather make you pay, for yet another subscription service instead.
So yes, you can kinda do it with an Internet TV too, assuming you trust the expensive box to not spy on you, but in that case you’re mostly just paying a whole lot more, for a lot less, than you would be, with the LG TV.
Also a “Publish who I follow” toggle: writes # follow = + # following = N into your feed like yarnd does. Off by default (it is your social graph 🤔), and only on the GitHub/Gitea backends for now where the app owns the feed file. twtd next 🤞
@GabesArcade@gabesarcade.com I think it would have to be specific to the App itself. So say you somehow didn’t save a recovery key or some shit™ You could still get back up and running with ease if you had exported a config? 🤔
Okay I’m fixing this in lextwt, yarnd and twtxt.app (takes a different path). Soon you’ll be able to write shit™ like (<this>) and it’ll get escaped and rendered correctly on the page. Basically you are really writing HTML here, but not intending to do so, Twtxt never supported HTML, and I don’t think it ever should. We extended the format to support basic Markdown, and I think that’s where it should end.
Probably time we wrote a Spec for this really.
@david@daiwei.me I see it now. Is this also a problem in the app too? Or just yarnd or both?
@movq@www.uninformativ.de You know you could in theory use the Twtxt App and the Twtxt Feeds service as your “news reader” right? 😅
Are you aware of the Residential Proxy pest?
https://spur.us/blog/smart-tv-apps-residential-proxy-sdks
This explains the access patterns that I see in my logs.
It’s funny, because I used to warn years ago that this might happen, and then I lost track of this topic. Now here we are and it’s a real issue. 🤦♀️
@aelaraji@aelaraji.com oh good was that the in app nudge?
Does this seem right to you so far @david@daiwei.me ? 🤔
2026/07/18 02:55:52 sync-reaper: observe-only pass — 1145 namespaces, 3 anchored, 1089 undatable, 0 idle candidate(s), 0 reaped
So far only 3 users of the Twtxt App have achieved their device settings with a recovery key? 🔑
📣 ACTION REQUIRED: Hey folks 👋 For those of you whom are using the Twtxt App either via the Hosted option or on your own twtd instnace or via Github/Gitea or any other publishing backend (doesn’t amtter). Please read.
Please open the app and you should be prompted to save your recovery code for your device. This basically is all of your settings, follows, etc in the app itself. This is synced to the Origin everytime you make a change, and also stored on-device. This is what makes it possible to sync your setting across services, move to another device, etc.
Please save a copy of the recovery code somewhere. This is only your only way to recover your settings.
Thank you 🙏
To retest: reload the app, reconnect Codeberg/Gitea with the same token, fill in the new Owner field (dce), repo twtxt, and Feed URL https://hashnix.club/~dce/twtxt.txt. Publish to Codeberg, serve from Hashnix — exactly what you wanted 🤞 lemme know!
@prologic@twtxt.net That’s more-or-less it. If I could do it without Codeberg (just using SCP, SSHFS, or something similar), that would be even better, but probably out-of-scope for the project.
My thinking behind how twtxt.app worked was that I could give it access to a repo, in order to add to my twtxt.txt, but that the alternative feed URL would then be presented to other users instead of the Codeberg URL; unless, of course, this is already part of the twtxt metadata.
In short, the feed URL would just be a dummy.
@dce@hashnix.club So let me get this straight… You want to store your feed on a Codeberg repo right? But you want to clone that repo down somewhere else to serve it on a different location. Right? And you’d like to use the Twtxt App (https://twtxt.app) to front all of this? Right?
@prologic@twtxt.net I created a repo called twtxt and an application key with read/write access to it (and only it). I then cloned the repo on Hashnix and hardlinked my twtxt into it, before committing and pushing. Next, I supplied the appropriate details on twtxt.app, under Codeberg/Gitea, and clicked “Connect”. gitea https://codeberg.org/api/v1/user: 403 Forbidden.
@prologic@twtxt.net I was actually trying to use twtxt.app, with Codeberg as a backend, but I kept getting a 403 error. As for twtd, well, my twtxt is hosted on a pubnix. The people behind Hashnix are really nice, but I’d rather not bother them with software requests if there’s a simpler solution, and I imagine it would be rude of me to run a deamon from my homedir without permission. Could be worth asking, though, unless I decide to write a client myself.
@dce@hashnix.club You may also be interested in the Twtxt App and the little tiny twtd publishing backend? 🤔
based on this, it’s entirely possible that there may still be a subtle bug somewhere with the app
I don’t think I’m going to add edit and delete support in this app because I think it was a horrible mistake to add those features to a client 🤣
twtpub.com is just the default instance tho — it’s a multi-tenant twtd, AGPLv3. Run your own and I’ll list it in the app’s picker so folks choose where to land 🤗 keeps it decentralised + spreads the load. Docs → https://git.mills.io/yarnsocial/twtd
New in the Twtxt App 🥳 a Hosted feed backend — claim a nick, one tap, no account, no server, nothing to run. Your feed lives at https://twtpub.com/u/yournick and you’re posting from the app straight away 🎉
Some further ideas/enhancements for Twtxt App …
- On the “Followers” tab, new followers should appear at the top I thnik.
- On the Following/Followers, each feed should be clickable/tappable.
- Maybe also tidy it up a bit, displaying the full raw Feed URI is messy.
@david@daiwei.me I agree, the App (https://twtxt.app) really does work quite nicely 👌
Hurray, I can now press gg instead of g to go to the top in tt. Much better! :-) Other multi-key combinations are also easily possible now.
I should probably write a real article about this at some point, but here we go. The only downside with my new key binding system is that it breaks tview’s established pattern. You’ve got an InputHandler(), that is implemented using WrapInputHandler(…). It typically then directly implements the switching logic depending on the key press. Something like this:
func (w *Widget) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
// WrapInputHandler allows for intercepting key events with SetInputCapture(…)
// from the outside for customization. This handles the default key bindings.
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
switch event.Key() {
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'k':
w.scrollUp()
return // we already handled the event, stop processing
case 'j':
w.scrollDown()
return
}
}
}
// We didn't handle the key event. Maybe the parent
// widget knows what to do with it.
if handler := w.parent.InputHandler(); handler != nil {
handler(event, setFocus)
}
})
}
From the outside, you can intercept and either stop or continue the widget’s original key handling with a potentially rewritten key event using SetInputCapture(…):
w := NewWidget()
// customized or additional key bindings
w.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() {
case tcell.KeyUp:
// Rewrite the event, so the "cursor up" key is an alias
// for the vim key binding "k", that is handled by the
// wrapped input handler above. (I know, I know, this is a
// completely unrealistic example, why would anyone use
// cursor keys when there are vim key bindings available?!)
return tcell.NewEventKey(tcell.KeyRune, 'k', tcell.ModNone)
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'q':
app.Stop()
// we already handled the event, do not pass it
// to the wrapped input handler above
return nil
case 'r':
toggleMessageReadStatus()
return nil
}
}
}
// we didn't handle the event, pass it to the wrapped
// input handler above
return event
}
Since they all expect a single key, I’ve noticed that using multiple dedicated KeyBindings of mine on these different levels kinda breaks multi-key handling with common prefixes. The outer-most KeyBinding captures the prefix, but it can’t transfer it to the inner one if not handled by the outer one. At least not without some more (potentially ugly) changes. So, I now have to work with just a single KeyBindings object for the entire widget chain (if it consists of multiple other widgets or the regular input handler and input capture are in the game). The outside needs to register all its key bind customizations or extensions at the same level that the original widget handles its default ones. Doable by exposing the widget’s KeyBindings instance, but not pretty. You always have to keep this in mind.
With the KeyBindings, it will look like that:
type Widget struct {
parent tview.Primitive
// make it available to children or the outside either by
// direct field access or by providing a getter method
KeyBindings *bind.KeyBindings
}
func NewWidget() *Widget {
w := &Widget{KeyBindings: &bind.KeyBindings{}}
w.KeyBindings. // default key bindings
Bind0(bind.KeySequence('k', w.scrollUp).
Bind0(bind.KeySequence('j', w.scrollDown)
return w
}
func (w *Widget) InputHandler() InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
// also note the missing support for focus transfer at the moment
event = w.KeyBindings.Capture(event)
if event == nil {
return
}
if handler := w.parent.InputHandler(); handler != nil {
handler(event, setFocus)
}
}
}
And then from the outside, or in a child widget:
w := NewWidget()
w.KeyBindings. // additional or customized key bindings
Bind1(bind.KeySequence(tcell.KeyUp), func(*tcell.EventKey) *tcell.EventKey {
return tcell.NewEventKey(tcell.KeyRune, 'k', tcell.ModNone)
}).
Bind0(bind.KeySequence('q'), app.Stop).
Bind0(bind.KeySequence('r'), toggleMessageReadStatus)
When directly working with tview primitives that are not part of custom widget implementations, the following works well so far:
textView := tview.NewTextView().
SetWordWrap(true).
SetText("…")
SetScrollable(true)
textView.SetInputCapture((&bind.KeyBindings{}).
Bind0(bind.KeySequence('q'), app.Stop).
Bind1(bind.KeySequence('g', 'g'), func(*tcell.EventKey) *tcell.EventKey {
return tcell.NewEventKey(tcell.KeyHome, 0, tcell.ModNone)
}).
Capture)
I need to sleep on this some more.
Also, writing very long messages like this one is really not all that fun in tt’s editor. I should absolutely provide a way to shell out to vim.
(Took me about one and a half hours to compose, holy crap. But not only because of not using vim. Although, that might have saved me a quarter hour or so for sure. Proof-reading this message also uncovered quite a few bugs in my real documentation. So, that’s a big win!) Good night!
Yeah this is my fault sorry! In this case i’ve axtually found yarns to be soex non-compliant 😱 Twtxt.app is doing yhe right thing🤣 As is Jammy 👌
@-mentions), unread dots, Back keeps your spot, and it'll now guide you to install it as a proper app 📱 Reload https://twtxt.app and have a play! Thanks @quark and @balloon-fu-sen for all the reports 🙏
Self-hosting twtd? Pull prologic/twtd:latest too — the Avatar URL field in the app now actually writes # avatar = into your feed (needed changes on both sides)
Shipped a bunch of Twtxt App fixes & polish today 🥳 One-tap Refresh that actually refreshes, duplicate follows fixed, Reply/Fork buttons (with proper @-mentions), unread dots, Back keeps your spot, and it’ll now guide you to install it as a proper app 📱 Reload https://twtxt.app and have a play! Thanks @quark@ferengi.one and @balloon-fu-sen@tw.fus.f5.si for all the reports 🙏
@balloon-fu-sen@tw.fus.f5.si Fixed! 🥳 The Avatar URL field now actually gets written to your feed’s # avatar = metadata. Turned out it needed changes in both the app and twtd itself — so you’ll want to update your twtd instance once the new build lands. Thanks for the report! 🙏
@prologic@twtxt.net I really like how these two apps pair-up. Seeing as I’m still tweaking TwtKpr, I’m considering adding support for the same APIs as twtd (so maybe it can be used as another backend for Twtxt.App). 🤔
@prologic@twtxt.net Le Me! both twtd and twtxt.app 👌
@balloonfu-sen@yarn.girlonthemoon.xyz I could in toehry publish a specification for what twtd implements, which forms the basis of the API between twtxt.app <-> twtd, if you wanted to write your own twtd / twtxt.app compatible publishing backend (assuming you didn’t want to use Github/Gitea, etc).
👍 definitely using the Twtxt App as my daily-driver now for Twtxt/Yarn. Not using twtd however, as I just pair the app with my already existing yarnd powered profile on twtxt.net
So… Quick count. Hands up those who are using the Twtxt App? 🤔 – And who’s also pairing this with the twtd publishing backend?
Looks like twtxt.app on mobile emits +00:00 UTC timestamps instead of Z – Yarnd should handle both, but doesn’t 🤦♂️ On the list 🤞
@bender@twtxt.net @david@daiwei.me Good debugging session 👌 Sounds like the root cause is twtxt.app on mobile — +00:00 timestamps and quoted mentions. I’ll dig into Yarnd’s side of that 🧐
@bender@twtxt.net Yeah, Yarnd’s mention parser is pretty naive — if twtxt.app wraps the mention in quotes it probably strips them wrong. Worth fixing 🤔
@david@daiwei.me bender variable in. First thing I see on Yarnd is that my mention is broken. It was entered between quotes on twtxt.app. Yarnd has always had parsing problems, so I am not blaming twtxt.app this time.
@movq@www.uninformativ.de this is what I see on twtxt.app (all looks good there, though, but not here, on Yarnd):
