Skip to content

Add KeeShare per-device sync support#2438

Open
Lcstyle wants to merge 16 commits into
Kunzisoft:developfrom
Lcstyle:feature/keeshare-pr
Open

Add KeeShare per-device sync support#2438
Lcstyle wants to merge 16 commits into
Kunzisoft:developfrom
Lcstyle:feature/keeshare-pr

Conversation

@Lcstyle

@Lcstyle Lcstyle commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Implements KeeShare per-device sync mode where each device writes its own container file ({DEVICE_ID}.kdbx) into a shared sync directory, eliminating file conflicts between devices
  • All file I/O through Android's Storage Access Framework (SAF) — no direct filesystem access, no network connections, no sync tool dependencies
  • Auto-sync via ContentObserver + periodic polling with import-only on detect, export-only on save (matches KeePassXC's ShareObserver pattern, prevents feedback loops)
  • Fixes DatabaseInputKDBX ignoring lastModificationTime on CustomData during KDBX parse

What's included

Commit Description
add KeeShare per-device sync core DeviceIdentity, KeeShareContainer, KeeShareExport, KeeShareImport, KeeShareReference, PerDeviceSyncConfig + unit tests
add KeeShare UI, SAF bridge, and sync manager KeeShareSyncRunnable, KeeShareSyncManager, settings UI, menu integration, share indicator icon
fix custom data lastModificationTime DatabaseInputKDBX.kt lines 543/595 — CustomData timestamps were being discarded
add KeeShare documentation End user guide, technical architecture doc, implementation design notes
fix KeeShareReference type parsing Use bitmask flags (ImportFrom=1, ExportTo=2) matching KeePassXC, add keepGroups support
add sync folder picker SAF-based folder picker in Settings > KeeShare with persistent URI permissions
add SAF folder provisioning prompt On first manual sync, prompts user to pick sync folder if not yet configured
improve import logging and merge tracking Per-group config logging, tracks actual new entries merged vs container count
fix KeeShare sync storm Auto-triggered syncs import-only (no export), 3s debounce, 5s min-interval guard
update user guide First-time setup flow, auto-sync behavior documentation, troubleshooting

Design principles

  • No file/folder management — only SAF data streams via content:// URIs
  • No sync tool integration — works with any folder sync tool (Syncthing, Nextcloud, etc.)
  • No network connections — purely local file operations
  • Interoperable with KeePassXC per-device mode — tested with real Syncthing sync between desktop and Pixel 7

Interop

Matching KeePassXC implementation: keepassxreboot/keepassxc#13080

Discussion: #2434

Test plan

  • Build succeeds (assembleLibreDebug + assembleLibreRelease)
  • Unit tests pass (DeviceIdentity, KeeShareContainer, PerDeviceSyncConfig)
  • Manual sync imports from KeePassXC container and exports own container
  • Auto-sync detects new containers via ContentObserver, imports only (no export)
  • Database save triggers export only (no import)
  • No sync storm between devices over Syncthing
  • First-time folder picker prompts correctly
  • Settings > KeeShare > Sync folder persists across restarts

KeeShare reference parsing (classic base64 XML), per-device sync
config (SAF URI-based), container read/write via streams, import/
export orchestration with scoped merge, device identity generation,
and group-level merge support in DatabaseKDBXMerger.

All I/O is stream-based — callers provide InputStream/OutputStream
lambdas. No direct filesystem access in this layer.
KeeShareSyncRunnable bridges core layer to SAF via DocumentFile and
ContentResolver streams. KeeShareSyncManager handles periodic sync,
export-on-save, and stale container cleanup.

UI: "Sync KeeShare" menu item in GroupActivity, result toast in
DatabaseLockActivity, share indicator on groups, settings screen
with device ID preference. All sync directory access uses SAF tree
URIs — no filesystem paths or inotify watchers.
Group and entry custom data items had their lastModificationTime
values read but discarded during XML parsing. This caused merge
conflict resolution in mergeCustomData() to always prefer incoming
data regardless of timestamps.
Implementation design doc, technical reference (keeshare-support.md),
and end-user setup guide covering both desktop and Android sides.
KeePassXC uses ImportFrom=1, ExportTo=2 as bitmask flags, not enum
ordinals. Also adds keepGroups support for per-device config.
SAF-based folder picker with persistent URI permissions. Shows
selected folder in preference summary.
When groups have a classic KeeShare/Reference from KeePassXC but no
PerDeviceSync config yet, prompts user to pick the local sync folder
before running sync.
Adds per-group config logging during import scan, tracks actual new
entries added vs container entry count.
Auto-triggered syncs (ContentObserver/polling) now only import — no
export. This matches KeePassXC's pattern where directory changes
trigger import-only, and database saves trigger export-only.

Also bumps ContentObserver debounce to 3s and adds 5s min-interval
guard to prevent rapid-fire re-triggers from Syncthing writes.
Documents the sync folder picker, first-time configuration flow,
import-only auto-sync vs export-on-save split, and new troubleshooting
entries.
Makes it explicit that KeePassXC must be configured first (writes
CustomData), then the database is copied to the phone, then KeePassDX
is configured. Adds root group sharing warning.
Track lastModified() per imported .kdbx file in SharedPreferences.
Before opening a stream (and triggering expensive Argon2 decryption),
compare the file's current mtime against the stored value and skip
if unchanged. Mtimes are persisted after each successful import.
When startAutoSync() runs, launch a one-shot check for newer container
files before waiting for the periodic poll. Catches files delivered by
Syncthing while the app was closed or locked.
@Lcstyle

Lcstyle commented Feb 25, 2026

Copy link
Copy Markdown
Contributor Author

Two additional commits pushed:

01cf821 — skip unchanged device files during import using per-file mtime tracking

Tracks lastModified() per imported .kdbx file in SharedPreferences. Before opening a stream (and triggering Argon2 decryption), the file's current mtime is compared against the stored value — if unchanged, the file is skipped entirely. Mtimes are persisted after each successful import. This avoids redundant decryption of container files that haven't been modified since the last sync.

69ce787 — trigger immediate sync when database is opened

When startAutoSync() runs, a one-shot check for newer container files is launched before waiting for the periodic 2-minute poll. This catches files delivered by Syncthing (or other sync tools) while the app was closed or locked, so the user sees up-to-date entries immediately on open rather than waiting for the next poll cycle.

Comment thread .github/workflows/release.yml Outdated
@@ -0,0 +1,91 @@
name: Release Build

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is part of the GitHub CD; it has no place in the PR.
Another issue is needed for this, the problem will be signing the APK with the keys currently used for production, although this may be useful for debug versions.

// all changes, e.g. files synced by external tools writing to filesystem)
periodicJob = CoroutineScope(Dispatchers.IO).launch {
while (isActive) {
delay(PERIODIC_SYNC_INTERVAL_MS)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My previous comment still stands: there should be no polling.

override fun onActionRun() {
Log.d(TAG, "=== KeeShare sync onActionRun() START ===")
try {
val kdbx = database.databaseKDBX

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The level of abstraction is not good. Historically, there may be actions that are performed directly on a specific type of database. But it needs to be generalized so that only the database type is used.


val deviceId = resolveDeviceId(context)
Log.d(TAG, "Device ID: $deviceId")
val cacheDir = File(context.cacheDir, "keeshare")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no direct cache in KeePassDX.

val data = result.data
if (data != null) {
val imported = data.getInt(
com.kunzisoft.keepass.database.action.KeeShareSyncRunnable.RESULT_IMPORTED_ENTRIES, 0)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no need to include the full package names for each constant. This is the case everywhere.

* but no KeeShare/PerDeviceSync custom data yet. The user needs to pick
* a local SAF directory for these.
*/
private var mPendingKeeShareGroups: List<com.kunzisoft.keepass.database.element.group.GroupKDBX> = emptyList()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new code must be placed in the viewModel; keeping this type of variable in the activities will make migration more difficult.

// Persist read/write access across reboots
val takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
contentResolver.takePersistableUriPermission(treeUri, takeFlags)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Permissions for opening files and folders should not be defined in the activity; instead, the common SAF code for opening files and folders should be aggregated.


/** Public read-only access to the KDBX database, or null if this is a KDB database */
val databaseKDBX: DatabaseKDBX?
get() = mDatabaseKDBX

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, there must be an abstraction so that there is no direct access to the database type. Even though the existing code may be written this way in several places, it is a legacy architecture from KeePassDroid and will be reviewed during migration.


**Branch**: `feature/keeshare-saf-refactor`
**Base**: `feature/keeshare-support`
**Date**: 2026-02-23

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file has no place in a PR.

Comment thread docs/keeshare-end-user-guide.md Outdated

- **ContentObserver**: Near-real-time detection of new files (fires within
seconds of your sync tool writing a new container)
- **Periodic poll**: Fallback check every 2 minutes in case the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContentObserver should be sufficient. If there is a failure, the application does not have to compensate for the file provider's problems.

@J-Jamet

J-Jamet commented Mar 2, 2026

Copy link
Copy Markdown
Member

There is a problem with the basic design of this feature.
KeeShare should typically do the same thing that a database without KeeShare can do. KeeShare is a special case of a sub-part of the database. With this feature, we basically define that a group is a database. So the database root group should behave and be able to perform exactly the same actions in the same way as one of its groups, but this is not the case here. KeeShare groups can do much more than the database Root group, which doesn't make sense.

Initially, KeePassDX was designed not to manage the concept of files at all and to abstract itself from the data type in order to process only data streams that can be saved anywhere (even in blobs scattered only in RAM if we want to implement it through SAF). But here, the concept of predefined files has been reimplemented by matching devices and even processing file names for a sub-feature, even though the Root database is not capable of doing so.
There cannot be a root base that manages fine granularity with “Save,” “Reload,” and “Merge,” which assumes that the content of a URI changes externally on the fly and that the user is given the choice to perform an action and high-level granularity that defines completely different conflict management.

The features must therefore remain consistent.

  • Either the current synchronization system must be changed. In this case, the user should not be given the option to name their KeePass master file either, and we would use the same concept that you want to implement. However, we would completely lose the advantage of allowing the user to choose where to save the file and rename it, and we would lose the main concept of KeePass, which is to save everything in a single file where we want.
  • Or KeeShare must also manage a low level of granularity by allowing users to manage only a single file. We know that the content of the URI will be modified and the three actions “Merge, Save, Reload” will apply in the same way to KeeShare groups data. The UI will need to be redesigned and there will be file conflicts, but that's just how the KeePass format works.

This feature as it is currently written adds many redundant concepts. In my opinion, creating a hybrid granularity system is a very bad idea, both for the creation of new features, which will be much more difficult to create because we will have to consider dual implementation, and for maintenance.
As I said in the first review, your idea for managing binary file conflicts is good, but in my opinion, it's just not in the right place. This concept of file conflict management by device must be managed upstream by the file manager which synchronizes files, which is different from synchronizing the data in those files. I'm currently recycle your proposal with the FileSync KMP application with a history system and manual manipulation of versions exposed by the URI so that it can be applied to all file types. There's no reason why only KeePass should benefit from it :p.
And the “Periodic poll” shouldn't be there; it's only there to compensate for problems with file managers that don't send the right file metadata, but ContentObserver should be sufficient. We therefore need to focus on resolving the metadata that's being reported rather than putting band-aids on the problem.

I haven't finished the review, but I've already spent a lot of time on it. ;)

@Lcstyle

Lcstyle commented Mar 2, 2026

Copy link
Copy Markdown
Contributor Author

KeeShare per-device mode exists in KeePassXC because file sync tools don't understand KDBX merge semantics. Syncthing can avoid file write conflicts, but it can't merge password entries from two databases.

That's why KeeShare splits into per-device files and then does KDBX-level merging.

Your alternative, "a generic FileSync app", would need to understand KDBX internals anyway to do meaningful merges, which defeats the "generic" purpose.

  1. He's describing the inherent architecture of KeeShare as designed by KeePassXC. These aren't bugs in your PR — they're features of the protocol.
  2. His alternative ("FileSync KMP will handle it") is vaporware — he says he's "currently recycling your proposal" but that app doesn't exist yet.
  3. The "everything should work identically" argument, taken to its logical conclusion, would mean either (a) the root database must auto-sync like KeeShare groups (massive redesign, loss of user control), or (b) KeeShare
    groups must use Save/Reload/Merge UI for every sync (terrible UX, defeats the purpose of auto-sync).
  4. His point about ContentObserver being sufficient is dogmatic — ContentObserver is known to be unreliable on various Android devices/providers.

Bottom line: His concerns are architecturally thoughtful but practically unrealistic. The hybrid approach is the standard KeeShare design (used by KeePassXC). His alternatives either don't exist yet or would require
fundamental redesigns that don't benefit users. He's not grasping at straws — he genuinely cares about architectural purity — but he's letting theoretical elegance override practical utility.

@Lcstyle

Lcstyle commented Mar 2, 2026

Copy link
Copy Markdown
Contributor Author

I've got a working solution, and my fork I've pushed working binaries. I'm using it already, so.... it is what it is.

Do what thou wilt.

@J-Jamet

J-Jamet commented Mar 2, 2026

Copy link
Copy Markdown
Member

Syncthing can avoid file write conflicts, but it can't merge password entries from two databases.

Yes, I understand. The idea is to offer the same URI that corresponds to a file but that will be merged when its content changes.

Your alternative, "a generic FileSync app", would need to understand KDBX internals anyway to do meaningful merges, which defeats the "generic" purpose.

No, that's the whole point of completely separating the concepts.

His alternative ("FileSync KMP will handle it") is vaporware

I didn't know what “vaporware” meant, so I looked up the definition. I'm working on this application locally, and creating a complete file manager is no easy task, especially if you want to integrate a versioning system. I decided to prioritize KeePassDX, which I think is the right choice. If FileSync isn't available yet, it's because there's no point in launching an application that's only half finished and has bugs. Vaporware? I realize it's easy to criticize, but I work on this in my spare time and I'm not under contract, so there are no deadlines and the project isn't canceled, apparently that's not the right term; so it's just there to disparage. I simply want to produce high-quality projects to try to compensate as much as possible for the mistakes of other apps that do not consider quality to be a requirement. Therefore, comments of this kind are not at all welcome.

The "everything should work identically" argument, taken to its logical conclusion, would mean either (a) the root database must auto-sync like KeeShare groups (massive redesign, loss of user control), or (b) KeeShare
groups must use Save/Reload/Merge UI for every sync (terrible UX, defeats the purpose of auto-sync).

Why terrible UX? It hasn't been done yet. Doing a little bit of both halfway isn't better, even if it meets your immediate needs, because it means there will be structural problems later on. You could say that since this is a future maintenance issue, we could just ignore it as long as it works now, but you know, that's not my style. ;)

His point about ContentObserver being sufficient is dogmatic — ContentObserver is known to be unreliable on various Android devices/providers.

If ContentObserver is known to be unreliable, why not propose corrections to the underlying problem? It's not ContentObserver that's not viable, it's the file providers who don't honor SAF contracts. These are two different things.

His concerns are architecturally thoughtful but practically unrealistic

I disagree. With another example, people said the same thing about Passkey, and it was still done entirely locally, it was unrealistic but theoretically feasible, and it was done. If there is a clear, long-term vision and the necessary resources are put in place, there is no reason why it shouldn't work. It may be unrealistic for one generation of fast code, but not over time.

His alternatives either don't exist yet or would require fundamental redesigns that don't benefit users. He's not grasping at straws — he genuinely cares about architectural purity — but he's letting theoretical elegance override practical utility.

I want to hear real arguments here, because it's specifically for the users that I want the architecture to remain clean and with a long-term vision. Thinking about the overall coherence of an ecosystem and solving structural problems are the very basis of tools designed for security. If practical utility means making compromises that would undermine the long-term stability of the application, that's not the basic philosophy here. Strong basis with is a conscious choice with real encapsulations has been part of the application since its inception and is the reason why it was created. So without arguments and without having understood that at first, again, it's just an AInsult.

I've got a working solution, and my fork I've pushed working binaries. I'm using it already, so.... it is what it is.
Do what thou wilt.

I appreciate your involvement, because it is very instructive, particularly with regard to the conditioned behavior of AI in relation to the context provided. I understand that most people want a basic tool that works but I don't understand why you give up so easily. As an anecdote, if I had stuck with that idea to have only one tool that works, KeePassDX wouldn't exist and I will continue to use KeePass2Android. The idea here is to have a healthy debate to create quality tools. If your fork meets your needs and those of other users, that's really great. I'm simply saying that features need to be thought out and designed holistically so that there are no structural problems in the long term.

- remove periodic polling from KeeShareSyncManager, keep ContentObserver
- make databaseKDBX internal to database module
- remove explicit cacheDirectory param from import/export
- add Database.forEachGroupWithCustomData helper
- replace FQN references with proper imports throughout
- use abstract Group type instead of GroupKDBX in activities
- use UriUtil.takeUriPermission for SAF permissions
- update end-user guide to remove polling references
@Lcstyle

Lcstyle commented Mar 3, 2026

Copy link
Copy Markdown
Contributor Author

Pushed fixes addressing review feedback:

Done:

  • Removed periodic polling — ContentObserver + sync-on-open only
  • databaseKDBX now internal — action/UI layer uses abstract Database/Group API only
  • Removed cacheDirectory param from import/export — uses binaryCache.cacheDirectory internally
  • Added Database.forEachGroupWithCustomData() helper for abstract group iteration
  • Replaced all FQN references with proper imports
  • GroupActivity.mPendingKeeShareGroups changed from List<GroupKDBX> to List<Group>
  • SAF permissions use UriUtil.takeUriPermission()
  • Deleted release.yml and design doc
  • Updated end-user guide (removed polling references)

Not done:

  • Menu visibility still uses allowDataCompression as KDBX proxy (no supportsKeeShare property added yet)
  • triggerExportAfterSave runs full sync, not export-only (no exportOnly flag added)

@Lcstyle

Lcstyle commented Mar 3, 2026

Copy link
Copy Markdown
Contributor Author

Ah, you know, the French can be credited with originating the word for sabotage — the sabot, the little wooden shoe flung into the gears, the romance of defiance, the worker’s shoe interrupting the march of industry. It is such a theatrical image, so satisfyingly dramatic. One can almost hear the clatter.

But the truth is less cinematic and far more amusing.

If the French contributed the poetry of obstruction, the Americans refined its technique. During the war, the OSS published a charmingly practical handbook titled Simple Sabotage. And what did it recommend? Not fire. Not force. Not shoes.

Meetings.

Insist on proper channels. Refer everything to committees. Request further study. Raise small procedural objections. Reopen settled decisions for “clarification.” Debate wording. Demand exhaustive documentation. Advocate caution in the name of responsibility. Pursue perfection with such devotion that nothing may proceed until it is immaculate.

Obstructionist Perfectionism.

You see, smashing the machine is crude. Anyone can break a gear. True obstruction is more elegant — it dresses itself as diligence, as prudence, as professionalism. It smiles warmly and says, “Let us be thorough.”

And so progress does not collapse in flames. It gently suffocates under minutes, subcommittees, and the noble pursuit of doing everything exactly right.

It is almost beautiful, in its way.

So tell me my dear Jamet why is a five year old project stuck on something I did in one day?

@J-Jamet

J-Jamet commented Mar 3, 2026

Copy link
Copy Markdown
Member

I don't see why I would sabotage a pull request for a feature that I also want and that would satisfy users? It makes no sense.

I was clear about my arguments, so in your opinion, if I were really a "saboteur", why would I waste my time doing this review and responding to your requests? I never said that the pull request would not be integrated. There are good things, and it's an interesting approach. I am just being cautious, especially regarding the architecture, security and maintenance, because this is a big PR and the first of this type that has been made, it duplicates concepts, and I don't understand why you are starting to get aggressive even though it is completely legitimate.

You may be expecting praise because it works, and since my review is slower than your automatic code generation, you don't like it, but what you're saying about nationality is completely irrelevant. Let me be very clear: I understand that there may be some frustration, but personal attacks, whether they involve politics, nationality, or anything else, are not allowed here.

In order to have a healthy exchange, I quickly put a review before this PR so that we can discuss and understand the project's challenges to find proper solutions. I could have completely set the feature aside, but instead I spent time, that I could have used elsewhere, because I think it's worth it.
So please respect this and don't make inappropriate remarks and speculation just because things aren't going your way.
Perhaps I am a perfectionist, but I am obviously open to good arguments, I am willing to discuss technical architectural choices, but if you are also willing to do so.

So tell me my dear Jamet why is a five year old project stuck on something I did in one day?

If you have created a file manager app that solves every file synchronization issues by managing multiple protocols independently and interoperably for any type of file even with blob, while providing a satisfying user experience, in one day, it's really really cool and I would be curious to see it.
But if you are referring to this generating code that was only contextualized according to your personal needs based on constraints solely by Syncthing on a pre-existing KeePass application, where guidelines are simply ignored or just modified on the fly based on a few lines of comments, that is something completely different.
The FileSync project was created several years ago just to describe the need that has been reported by many users for years, but its development began more recently because I didn't have the time and resources to devote to it before, as I said. But if mentioning this project bothers you, no worries, we assume that this is not a real solution because it does not exist yet for the public.

Once again, I am not limiting new ways of creation, as they can be very helpful and allow for rapid execution. I thank you for the PR, that's very interesting, but please understand that I have to conduct a thorough study before rolling it out to all users. I don't have much room for error, and of course I'm the one who has to play the "bad guy" and who must thoroughly check. I'm not thrilled about it and I don't like that but it's necessary and healthy. Architectural choices of KeePassDX must simply remain consistent. And instead of arguing about the hybrid architecture choices you made, you emphasize the speed of execution and make personal attacks, why?
Please stick to technical matters and discuss topics that will help resolve sticking points. If you are certain about what you put forward in the previous PR code, why did you generated new code by following just new comments if you disagree with them without really arguing?

The problem has never been generating code that works, but rather code that works and is properly structured and designed for long-term maintenance. If you are certain that your architecture is sound and you are prepared to perform maintenance for years to come and manage future friction that you did not anticipate when accepting the code, you already have your fork, so it's a win-win for you, and that's the whole point of open source.

I haven't looked at the new code yet, I'll put the actual review in version 4.5.0. https://github.com/Kunzisoft/KeePassDX/projects?query=is%3Aopen

@LecrisUT

Copy link
Copy Markdown

This PR seems to be dead on arrival unless the author (be it the AI agent or the person submitting it) can follow the basic design requirements laid out (all of which was specified in the original issue). At the bare minimum this PR needs to be split out into a few interdependent PRs:

  • Ability to open multiple databases
  • Keeshare functionality in read-only mode
  • Keeshare functionality in write/synchronization mode
  • Additional features that have not been accepted in KeepassXC yet

@Lcstyle you are probably new to open source contribution and do not realize how big of a burden you are putting on others with AI generated code. If you are serious about wanting this feature and sharing it with others then be considerate and lower this burden by splitting things into smaller bits and making them more reviewable.

I have had an unfortunate enough experience at my day job dealing with AI PRs and I can tell you that this PR in this current state will require at least 300 comments back-and-forth spanning probably a year. If things are split up small enough the AI is actually better at aligning with the intended direction and re-use existing code, cutting this down to maybe 20-40 comments over a few weeks to a month.

@J-Jamet unfortunately this is the kind of things that we have to deal with these days. The only way that I managed to stay sane about things is to not go into details and just state the bare minimum. It helps to consider that all the effort you put in the reply often does not go to the author and it is just copy-pasted into the chatbot.

For the cases where people use AI ethically the user does not just present you with AI responses, instead they properly review the code and can respond more concise with a human voice.

So don't be shy about being more direct about handling these situations in ways that are more beneficial to your mental well-being. The AI chatbots are not considerate towards that.

@J-Jamet J-Jamet removed this from KeePassDX 4.6.0 May 5, 2026
@dbankmann

Copy link
Copy Markdown

I've taken the liberty to give this a shot in #2544 . Please have a look, and let me know if splitting it up into more pr according to the individual commits would help reviewing. Disclaimer: I've used AI assistance for this, but kept being in the loop trying to understand and more importantly steer it to some solution, that seemed architecturally sound.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

5 participants