The problem with intuition is that it's different for everyone, so what's intuitive for one person is confusing to another. In this case, you have to understand some of Rust's build process before the solution makes sense. The common library code and the apps are each a separate crate¹, so using the crate keyword inside app1 will only ever refer to something inside the src/app1 directory— You need to refer to the library like it's something you imported from crates.io.
Additionally, your directory structure differs from the standard one, which may also be causing problems. Usually, your project would be laid out like this:
You may not believe it, but Rust's approach is simple. It is just significantly different than what other languages do, which makes it confusing until you learn it. But Rust chose this approach, because it has some advantages:
all modules can be discovered from the source code, without scanning directories (unlike Go). This allows controlling of module's existence through normal cfg directives, is fast even if you have lots of other files in the project, and "leftover" files in the filesystem don't get compiled by accident.
there's no textual inclusion (unlike C and C++), so modules are properly encapsulated and namespaced.
modules are defined by their logical path, not file system path, so the inline mod {} syntax is possible (often useful in macros).
mod definition is consistent with definitions of fn, struct, enum, and const, and all of these items can be used in the same way. Other languages treat modules/packages in a special way that is inconsistent with how they define anything else. Your intuition probably expects the special behavior.