diff --git a/Cargo.toml b/Cargo.toml
index 55f320b..7785627 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,28 +1,8 @@
-[package]
-name = "r701"
-version = "0.2.0"
+[workspace]
+resolver = "3"
+members = ["r701"]
+
+[workspace.package]
edition = "2021"
license = "AGPL-3.0-or-later"
repository = "https://git.nicolabelluti.me/nicolabelluti/r701"
-
-[dependencies]
-async-stream = "0.3.6"
-chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
-serde = { version = "1.0.203", default-features = false, features = ["derive"], optional = true }
-tokio = { version = "1.53.1", default-features = false, features = ["net", "io-util", "sync"] }
-tokio-stream = { version = "0.1.19", default-features = false }
-
-[features]
-serde = ["chrono/serde", "dep:serde"]
-
-[lints.rust]
-unsafe_code = "forbid"
-
-[lints.clippy]
-unwrap_used = "deny"
-enum_glob_use = { level = "deny", priority = 1 }
-pedantic = { level = "deny", priority = -1 }
-nursery = { level = "deny", priority = -1 }
-
-[dev-dependencies]
-tokio = { version = "1.53.1", features = ["rt", "macros", "net"] }
diff --git a/README.md b/README.md
index 34dafba..360f15f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-# R701 🕰️
+# R701 | Oxibadge
[](https://www.rust-lang.org)
[](https://claude.com/product/claude-code)
@@ -11,58 +11,16 @@
-> A reverse-engineered library to communicate with the
-> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) by [I.P.S.
-> Informatica](https://ipsinformatica.info/), written in Rust
+> A reverse-engineered client for the
+> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) attendance reader by
+> [I.P.S. Informatica](https://ipsinformatica.info/)
-If you want to read about this reverse engineering attempt, check out
-.
+This repository is a Cargo workspace with two members:
-## Library Usage
+- **[`r701/`](r701/README.md)** — the async Rust library that speaks the
+ device's TCP protocol.
+- **`oxibadge/`** — Oxibadge, a minimal Tauri + Svelte desktop client built on
+ top of the library. *(Coming soon.)*
-1. Add the library to you project:
-
- ```shell
- cargo add r701 --git https://git.nicolabelluti.me/nicolabelluti/r701.git
- ```
-
-2. Use the library in you project:
-
- This library is async and built on [tokio](https://tokio.rs); add it to your
- own `[dependencies]` (e.g. `tokio = { version = "1", features =
- ["rt-multi-thread", "macros"] }`) to run the example below.
-
- ```rust
- use r701::R701;
- use tokio_stream::StreamExt;
-
- #[tokio::main]
- async fn main() {
- let r701 = R701::connect("127.0.0.1:5005").await.unwrap();
- let mut record_stream = r701.into_record_iter().await.unwrap();
- let mut id = 0;
-
- println!("No\tMchn\tEnNo\t\tName\t\tMode\tIOMd\tDateTime\t");
- while let Some(record) = record_stream.next().await {
- let record = record.unwrap();
- let name = match r701.get_name(record.employee_id).await.unwrap() {
- Some(Ok(name)) => name,
- Some(Err(error)) => String::from_utf8_lossy(error.as_bytes()).into_owned(),
- None => format!("user #{}", record.employee_id),
- };
-
- println!(
- "{:0>6}\t{}\t{:0>9}\t{: <10}\t{}\t{}\t{}",
- id + 1,
- 1,
- record.employee_id,
- name,
- 35,
- record.clock as u8,
- record.datetime.format("%Y/%m/%d %H:%M:%S"),
- );
-
- id += 1;
- }
- }
- ```
+If you want to read about the reverse engineering attempt behind the library,
+check out .
diff --git a/r701/Cargo.toml b/r701/Cargo.toml
new file mode 100644
index 0000000..16ab2a8
--- /dev/null
+++ b/r701/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "r701"
+version = "0.2.0"
+edition.workspace = true
+license.workspace = true
+repository.workspace = true
+
+[dependencies]
+async-stream = "0.3.6"
+chrono = { version = "0.4.38", default-features = false, features = ["clock"] }
+serde = { version = "1.0.203", default-features = false, features = ["derive"], optional = true }
+tokio = { version = "1.53.1", default-features = false, features = ["net", "io-util", "sync"] }
+tokio-stream = { version = "0.1.19", default-features = false }
+
+[features]
+serde = ["chrono/serde", "dep:serde"]
+
+[lints.rust]
+unsafe_code = "forbid"
+
+[lints.clippy]
+unwrap_used = "deny"
+enum_glob_use = { level = "deny", priority = 1 }
+pedantic = { level = "deny", priority = -1 }
+nursery = { level = "deny", priority = -1 }
+
+[dev-dependencies]
+tokio = { version = "1.53.1", features = ["rt", "macros", "net"] }
diff --git a/r701/README.md b/r701/README.md
new file mode 100644
index 0000000..34dafba
--- /dev/null
+++ b/r701/README.md
@@ -0,0 +1,68 @@
+
+
+# R701 🕰️
+
+[](https://www.rust-lang.org)
+[](https://claude.com/product/claude-code)
+[](https://choosealicense.com/licenses/agpl-3.0)
+[](https://buymeacoffee.com/nicolabelluti)
+
+[](https://git.nicolabelluti.me/nicolabelluti/r701/actions/?workflow=check-format-and-test.yaml)
+
+
+
+> A reverse-engineered library to communicate with the
+> [R701](https://ipsattendant.it/rilevatore-presenze-r701/) by [I.P.S.
+> Informatica](https://ipsinformatica.info/), written in Rust
+
+If you want to read about this reverse engineering attempt, check out
+.
+
+## Library Usage
+
+1. Add the library to you project:
+
+ ```shell
+ cargo add r701 --git https://git.nicolabelluti.me/nicolabelluti/r701.git
+ ```
+
+2. Use the library in you project:
+
+ This library is async and built on [tokio](https://tokio.rs); add it to your
+ own `[dependencies]` (e.g. `tokio = { version = "1", features =
+ ["rt-multi-thread", "macros"] }`) to run the example below.
+
+ ```rust
+ use r701::R701;
+ use tokio_stream::StreamExt;
+
+ #[tokio::main]
+ async fn main() {
+ let r701 = R701::connect("127.0.0.1:5005").await.unwrap();
+ let mut record_stream = r701.into_record_iter().await.unwrap();
+ let mut id = 0;
+
+ println!("No\tMchn\tEnNo\t\tName\t\tMode\tIOMd\tDateTime\t");
+ while let Some(record) = record_stream.next().await {
+ let record = record.unwrap();
+ let name = match r701.get_name(record.employee_id).await.unwrap() {
+ Some(Ok(name)) => name,
+ Some(Err(error)) => String::from_utf8_lossy(error.as_bytes()).into_owned(),
+ None => format!("user #{}", record.employee_id),
+ };
+
+ println!(
+ "{:0>6}\t{}\t{:0>9}\t{: <10}\t{}\t{}\t{}",
+ id + 1,
+ 1,
+ record.employee_id,
+ name,
+ 35,
+ record.clock as u8,
+ record.datetime.format("%Y/%m/%d %H:%M:%S"),
+ );
+
+ id += 1;
+ }
+ }
+ ```
diff --git a/src/lib.rs b/r701/src/lib.rs
similarity index 100%
rename from src/lib.rs
rename to r701/src/lib.rs
diff --git a/src/r701.rs b/r701/src/r701.rs
similarity index 100%
rename from src/r701.rs
rename to r701/src/r701.rs
diff --git a/src/record.rs b/r701/src/record.rs
similarity index 100%
rename from src/record.rs
rename to r701/src/record.rs
diff --git a/src/record_iterator.rs b/r701/src/record_iterator.rs
similarity index 100%
rename from src/record_iterator.rs
rename to r701/src/record_iterator.rs
diff --git a/tests/e2e.rs b/r701/tests/e2e.rs
similarity index 100%
rename from tests/e2e.rs
rename to r701/tests/e2e.rs
diff --git a/tests/mock/mod.rs b/r701/tests/mock/mod.rs
similarity index 100%
rename from tests/mock/mod.rs
rename to r701/tests/mock/mod.rs